mirror of
https://github.com/open5gs/open5gs.git
synced 2025-11-02 13:03:31 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb2e976958 | ||
|
|
4165ec1264 | ||
|
|
540a3956bb | ||
|
|
9919e7dc86 | ||
|
|
6bd8411fc1 | ||
|
|
8fea12643a | ||
|
|
c964d1df3c | ||
|
|
ddaea685b3 | ||
|
|
e1ad9c43d7 | ||
|
|
0b91d42cb1 | ||
|
|
653701abdb | ||
|
|
58bcda332b | ||
|
|
8cb620e477 | ||
|
|
5cac796e46 | ||
|
|
8c68560ccd | ||
|
|
b2c6c8f856 | ||
|
|
f753d38338 | ||
|
|
c711e788d2 | ||
|
|
26f4081979 | ||
|
|
3427835ecc | ||
|
|
7312dd1974 | ||
|
|
f5599896ff | ||
|
|
aea1d83026 | ||
|
|
3dc2d396db |
@@ -86,6 +86,11 @@ If you don't understand something about NextEPC, the [http://nextepc.org](http:/
|
||||
Problem with NextEPC can be filed as [issues](https://github.com/acetcom/nextepc/issues) in this repository. And also, we've created *Discord* workspace for _nextepc_. Use [this link](https://discord.gg/GreNkuc) to get started.
|
||||
|
||||
|
||||
## Mailing List
|
||||
|
||||
Discussions related to this project are happening on the nextepc@lists.osmocom.org mailing list, please see <https://lists.osmocom.org/mailman/listinfo/nextepc> for subscription options and the list archive.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
NextEPC source files are made available under the terms of the GNU Affero General Public License (GNU AGPLv3). See [this link](http://nextepc.org/docs/nextepc/4-license/) for details.
|
||||
|
||||
@@ -8,7 +8,7 @@ dnl This program is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
AC_INIT([NextEPC], [0.3.10], [acetcom@gmail.com])
|
||||
AC_INIT([NextEPC], [0.3.11], [acetcom@gmail.com])
|
||||
|
||||
AC_SUBST(LIBVERSION)
|
||||
LIBVERSION=1:0:0
|
||||
|
||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
||||
nextepc (0.3.11~bionic) bionic; urgency=medium
|
||||
|
||||
* Bug Fixed
|
||||
|
||||
-- Sukchan Lee <acetcom@gmail.com> Sat, 27 Apr 2019 13:59:08 +0000
|
||||
|
||||
nextepc (0.3.11~xenial) xenial; urgency=medium
|
||||
|
||||
* Bug Fixed
|
||||
|
||||
-- Sukchan Lee <acetcom@gmail.com> Sat, 27 Apr 2019 13:57:42 +0000
|
||||
|
||||
nextepc (0.3.10~xenial) xenial; urgency=medium
|
||||
|
||||
* Bug Fixed
|
||||
|
||||
@@ -14,6 +14,9 @@ extern "C" {
|
||||
#define SCTP_S1AP_PPID 18
|
||||
#define SCTP_X2AP_PPID 27
|
||||
|
||||
#define MAX_NUM_OF_SGW 32
|
||||
#define MAX_NUM_OF_PGW 32
|
||||
|
||||
#define MAX_NUM_OF_ENB 128
|
||||
#define MAX_NUM_OF_UE 128
|
||||
#define MAX_NUM_OF_SESS 4
|
||||
@@ -87,13 +90,6 @@ typedef struct _e_cgi_t {
|
||||
c_uint32_t cell_id; /* 28 bit */
|
||||
} __attribute__ ((packed)) e_cgi_t;
|
||||
|
||||
typedef struct _guti_t {
|
||||
plmn_id_t plmn_id;
|
||||
c_uint16_t mme_gid;
|
||||
c_uint8_t mme_code;
|
||||
c_uint32_t m_tmsi;
|
||||
} __attribute__ ((packed)) guti_t;
|
||||
|
||||
/**************************************************
|
||||
* Common Structure
|
||||
* S1AP : 9.2.2.1 Transport Layer Address, See 36.414
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include "core_debug.h"
|
||||
#include "core_pool.h"
|
||||
|
||||
#define MAX_NUM_OF_CLBUF 256
|
||||
#define MAX_NUM_OF_PKBUF 256
|
||||
#define MAX_NUM_OF_CLBUF (8192 + 4096 + 2048 + 1024 + 512 + 128)
|
||||
#define MAX_NUM_OF_PKBUF (8192 + 4096 + 2048 + 1024 + 512 + 128)
|
||||
|
||||
pool_declare(clbuf_pool, clbuf_t, MAX_NUM_OF_CLBUF);
|
||||
pool_declare(pkbuf_pool, pkbuf_t, MAX_NUM_OF_PKBUF);
|
||||
@@ -23,12 +23,12 @@ pool_declare(pkbuf_pool, pkbuf_t, MAX_NUM_OF_PKBUF);
|
||||
#define SIZEOF_CLUSTER_2048 CORE_ALIGN(2048+MAX_SIZEOF_HEADROOM, BOUNDARY)
|
||||
#define SIZEOF_CLUSTER_8192 CORE_ALIGN(8192+MAX_SIZEOF_HEADROOM, BOUNDARY)
|
||||
|
||||
#define MAX_NUM_OF_CLUSTER_128 256
|
||||
#define MAX_NUM_OF_CLUSTER_256 256
|
||||
#define MAX_NUM_OF_CLUSTER_512 256
|
||||
#define MAX_NUM_OF_CLUSTER_1024 256
|
||||
#define MAX_NUM_OF_CLUSTER_2048 256
|
||||
#define MAX_NUM_OF_CLUSTER_8192 256
|
||||
#define MAX_NUM_OF_CLUSTER_128 8192
|
||||
#define MAX_NUM_OF_CLUSTER_256 4096
|
||||
#define MAX_NUM_OF_CLUSTER_512 2048
|
||||
#define MAX_NUM_OF_CLUSTER_1024 1024
|
||||
#define MAX_NUM_OF_CLUSTER_2048 512
|
||||
#define MAX_NUM_OF_CLUSTER_8192 128
|
||||
|
||||
typedef c_uint8_t cluster_128_t[SIZEOF_CLUSTER_128];
|
||||
typedef c_uint8_t cluster_256_t[SIZEOF_CLUSTER_256];
|
||||
|
||||
@@ -28,14 +28,13 @@ status_t gtp_node_final(void)
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t gtp_add_node(list_t *list, gtp_node_t **node,
|
||||
status_t gtp_create_node(gtp_node_t **node,
|
||||
c_sockaddr_t *all_list, int no_ipv4, int no_ipv6, int prefer_ipv4)
|
||||
{
|
||||
status_t rv;
|
||||
gtp_node_t *new_node = NULL;
|
||||
c_sockaddr_t *preferred_list = NULL;
|
||||
|
||||
d_assert(list, return CORE_ERROR,);
|
||||
d_assert(all_list, return CORE_ERROR,);
|
||||
|
||||
rv = core_copyaddrinfo(&preferred_list, all_list);
|
||||
@@ -71,8 +70,6 @@ status_t gtp_add_node(list_t *list, gtp_node_t **node,
|
||||
|
||||
list_init(&new_node->local_list);
|
||||
list_init(&new_node->remote_list);
|
||||
|
||||
list_append(list, new_node);
|
||||
}
|
||||
|
||||
*node = new_node;
|
||||
@@ -80,7 +77,22 @@ status_t gtp_add_node(list_t *list, gtp_node_t **node,
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
gtp_node_t *gtp_add_node_with_teid(list_t *list, gtp_f_teid_t *f_teid,
|
||||
status_t gtp_delete_node(gtp_node_t *node)
|
||||
{
|
||||
d_assert(node, return CORE_ERROR,);
|
||||
|
||||
if (node->sock)
|
||||
sock_delete(node->sock);
|
||||
|
||||
gtp_xact_delete_all(node);
|
||||
|
||||
core_freeaddrinfo(node->sa_list);
|
||||
pool_free_node(>p_node_pool, node);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
gtp_node_t *gtp_add_node(list_t *list, gtp_f_teid_t *f_teid,
|
||||
c_uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4)
|
||||
{
|
||||
status_t rv;
|
||||
@@ -94,9 +106,16 @@ gtp_node_t *gtp_add_node_with_teid(list_t *list, gtp_f_teid_t *f_teid,
|
||||
rv = gtp_f_teid_to_sockaddr(f_teid, port, &sa_list);
|
||||
d_assert(rv == CORE_OK, return NULL,);
|
||||
|
||||
rv = gtp_add_node(list, &node, sa_list, no_ipv4, no_ipv6, prefer_ipv4);
|
||||
rv = gtp_create_node(&node, sa_list, no_ipv4, no_ipv6, prefer_ipv4);
|
||||
d_assert(rv == CORE_OK, return NULL,);
|
||||
d_assert(node, return NULL,);
|
||||
if (node == NULL)
|
||||
{
|
||||
d_error("Invalid Parameter : "
|
||||
"port[%d], no_ipv4[%d], no_ipv6[%d], prefer_ipv4[%d]",
|
||||
port, no_ipv4, no_ipv6, prefer_ipv4);
|
||||
return NULL;
|
||||
}
|
||||
list_append(list, node);
|
||||
|
||||
rv = gtp_f_teid_to_ip(f_teid, &node->ip);
|
||||
d_assert(rv == CORE_OK, return NULL,);
|
||||
@@ -111,19 +130,15 @@ gtp_node_t *gtp_add_node_with_teid(list_t *list, gtp_f_teid_t *f_teid,
|
||||
|
||||
status_t gtp_remove_node(list_t *list, gtp_node_t *node)
|
||||
{
|
||||
status_t rv;
|
||||
d_assert(node, return CORE_ERROR,);
|
||||
|
||||
list_remove(list, node);
|
||||
|
||||
if (node->sock)
|
||||
sock_delete(node->sock);
|
||||
rv = gtp_delete_node(node);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
gtp_xact_delete_all(node);
|
||||
|
||||
core_freeaddrinfo(node->sa_list);
|
||||
pool_free_node(>p_node_pool, node);
|
||||
|
||||
return CORE_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
status_t gtp_remove_all_nodes(list_t *list)
|
||||
|
||||
@@ -35,9 +35,11 @@ typedef struct _gtp_node_t {
|
||||
CORE_DECLARE(status_t) gtp_node_init(void);
|
||||
CORE_DECLARE(status_t) gtp_node_final(void);
|
||||
|
||||
CORE_DECLARE(status_t) gtp_add_node(list_t *list, gtp_node_t **node,
|
||||
c_sockaddr_t *sa_list, int no_ipv4, int no_ipv6, int prefer_ipv4);
|
||||
CORE_DECLARE(gtp_node_t *) gtp_add_node_with_teid(
|
||||
CORE_DECLARE(status_t) gtp_create_node(gtp_node_t **node,
|
||||
c_sockaddr_t *all_list, int no_ipv4, int no_ipv6, int prefer_ipv4);
|
||||
CORE_DECLARE(status_t) gtp_delete_node(gtp_node_t *node);
|
||||
|
||||
CORE_DECLARE(gtp_node_t *) gtp_add_node(
|
||||
list_t *list, gtp_f_teid_t *f_teid,
|
||||
c_uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4);
|
||||
CORE_DECLARE(status_t) gtp_remove_node(list_t *list, gtp_node_t *node);
|
||||
|
||||
@@ -379,14 +379,18 @@ ED3(c_uint8_t ipv4:1;,
|
||||
#define GTP_UE_TIME_ZONE_NO_ADJUSTMENT_FOR_DAYLIGHT_SAVING_TIME 0
|
||||
#define GTP_UE_TIME_ZONE_1_HOUR_FOR_DAYLIGHT_SAVING_TIME 1
|
||||
#define GTP_UE_TIME_ZONE_2_HOUR_FOR_DAYLIGHT_SAVING_TIME 2
|
||||
/* Time Zone" IE in 3GPP TS 24.008 [5].
|
||||
* This field uses the same format as the Timezone field used in the
|
||||
* TP-Service-Centre-Time-Stamp, which is defined in 3GPP TS 23.040 [90],
|
||||
* and its value shall be set as defined in 3GPP TS 22.042 */
|
||||
typedef struct _gtp_ue_timezone_t {
|
||||
/* Time Zone" IE in 3GPP TS 24.008 [5].
|
||||
* This field uses the same format as the Timezone field used in the
|
||||
* TP-Service-Centre-Time-Stamp, which is defined in 3GPP TS 23.040 [90],
|
||||
* and its value shall be set as defined in 3GPP TS 22.042 */
|
||||
#define GTP_TIME_TO_BCD(x) TIME_TO_BCD(x)
|
||||
ED2(c_uint8_t sign:1;,
|
||||
c_uint8_t gmtoff:7;) /* quarters of an hour */
|
||||
/* The Time Zone indicates the difference, expressed in quarters of an hour,
|
||||
* between the local time and GMT. In the first of the two semi-octets,
|
||||
* the first bit (bit 3 of the seventh octet of
|
||||
* the TP-Service-Centre-Time-Stamp field) represents
|
||||
* the algebraic sign of this difference (0: positive, 1: negative). */
|
||||
c_uint8_t timezone;
|
||||
ED2(c_uint8_t spare:6;,
|
||||
c_uint8_t daylight_saving_time:2;)
|
||||
} __attribute__ ((packed)) gtp_ue_timezone_t;
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* This file had been created by gtpv2c_tlv.py script v0.1.0
|
||||
* This file had been created by nas_message.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2018-01-23 15:58:42.874567 by acetcom
|
||||
* Created on: 2019-03-17 01:58:02.778431 by acetcom
|
||||
* from 24301-d80.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* This file had been created by gtpv2c_tlv.py script v0.1.0
|
||||
* This file had been created by nas_message.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2018-01-23 15:58:42.903985 by acetcom
|
||||
* Created on: 2019-03-17 01:58:02.809354 by acetcom
|
||||
* from 24301-d80.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* This file had been created by gtpv2c_tlv.py script v0.1.0
|
||||
* This file had been created by nas_message.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2018-01-23 15:58:42.829935 by acetcom
|
||||
* Created on: 2019-03-17 01:58:02.731397 by acetcom
|
||||
* from 24301-d80.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* This file had been created by gtpv2c_tlv.py script v0.1.0
|
||||
* This file had been created by nas_message.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2018-01-23 15:58:42.823738 by acetcom
|
||||
* Created on: 2019-03-17 01:58:02.723555 by acetcom
|
||||
* from 24301-d80.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* This file had been created by gtpv2c_tlv.py script v0.1.0
|
||||
* This file had been created by nas_message.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2018-01-23 15:58:42.847411 by acetcom
|
||||
* Created on: 2019-03-17 01:58:02.754073 by acetcom
|
||||
* from 24301-d80.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
@@ -5,6 +5,29 @@
|
||||
|
||||
#include "nas_types.h"
|
||||
|
||||
void *nas_from_plmn_id(nas_plmn_id_t *nas_plmn_id, plmn_id_t *plmn_id)
|
||||
{
|
||||
memcpy(nas_plmn_id, plmn_id, PLMN_ID_LEN);
|
||||
if (plmn_id->mnc1 != 0xf)
|
||||
{
|
||||
nas_plmn_id->mnc1 = plmn_id->mnc1;
|
||||
nas_plmn_id->mnc2 = plmn_id->mnc2;
|
||||
nas_plmn_id->mnc3 = plmn_id->mnc3;
|
||||
}
|
||||
return nas_plmn_id;
|
||||
}
|
||||
void *nas_to_plmn_id(plmn_id_t *plmn_id, nas_plmn_id_t *nas_plmn_id)
|
||||
{
|
||||
memcpy(plmn_id, nas_plmn_id, PLMN_ID_LEN);
|
||||
if (plmn_id->mnc1 != 0xf)
|
||||
{
|
||||
plmn_id->mnc1 = nas_plmn_id->mnc1;
|
||||
plmn_id->mnc2 = nas_plmn_id->mnc2;
|
||||
plmn_id->mnc3 = nas_plmn_id->mnc3;
|
||||
}
|
||||
return plmn_id;
|
||||
}
|
||||
|
||||
static c_uint8_t br_calculate(
|
||||
c_uint8_t *br, c_uint8_t *extended, c_uint8_t *extended2,
|
||||
c_uint64_t input)
|
||||
@@ -229,6 +252,7 @@ void nas_tai_list_build(
|
||||
|
||||
tai0_list_t target0;
|
||||
tai2_list_t target2;
|
||||
nas_plmn_id_t nas_plmn_id;
|
||||
|
||||
d_assert(target, return,);
|
||||
d_assert(source0, return,);
|
||||
@@ -249,7 +273,8 @@ void nas_tai_list_build(
|
||||
return, "num = %d", source0->tai[i].num);
|
||||
target0.tai[i].num = source0->tai[i].num - 1;
|
||||
memcpy(&target0.tai[i].plmn_id,
|
||||
&source0->tai[i].plmn_id, PLMN_ID_LEN);
|
||||
nas_from_plmn_id(&nas_plmn_id, &source0->tai[i].plmn_id),
|
||||
PLMN_ID_LEN);
|
||||
|
||||
for (j = 0; j < source0->tai[i].num; j++)
|
||||
{
|
||||
@@ -290,7 +315,8 @@ void nas_tai_list_build(
|
||||
for (i = 0; i < source2->num; i++)
|
||||
{
|
||||
memcpy(&target2.tai[i].plmn_id,
|
||||
&source2->tai[i].plmn_id, PLMN_ID_LEN);
|
||||
nas_from_plmn_id(&nas_plmn_id, &source2->tai[i].plmn_id),
|
||||
PLMN_ID_LEN);
|
||||
target2.tai[i].tac = htons(source2->tai[i].tac);
|
||||
}
|
||||
memcpy(target->buffer + target->length, &target2, size);
|
||||
|
||||
@@ -30,6 +30,27 @@ extern "C" {
|
||||
|
||||
#define NAS_KSI_NO_KEY_IS_AVAILABLE 0x7
|
||||
|
||||
/**********************************
|
||||
* NAS PLMN_ID Structure */
|
||||
typedef struct _nas_plmn_id_t {
|
||||
ED2(uint8_t mcc2:4;,
|
||||
uint8_t mcc1:4;)
|
||||
ED2(uint8_t mnc3:4;,
|
||||
uint8_t mcc3:4;)
|
||||
ED2(uint8_t mnc2:4;,
|
||||
uint8_t mnc1:4;)
|
||||
} __attribute__ ((packed)) nas_plmn_id_t;
|
||||
|
||||
void *nas_from_plmn_id(nas_plmn_id_t *nas_plmn_id, plmn_id_t *plmn_id);
|
||||
void *nas_to_plmn_id(plmn_id_t *plmn_id, nas_plmn_id_t *nas_plmn_id);
|
||||
|
||||
typedef struct _guti_t {
|
||||
nas_plmn_id_t plmn_id;
|
||||
uint16_t mme_gid;
|
||||
uint8_t mme_code;
|
||||
uint32_t m_tmsi;
|
||||
} __attribute__ ((packed)) guti_t;
|
||||
|
||||
/* 9.9.2.0 Additional information
|
||||
* O TLV 3-n */
|
||||
#define NAX_MAX_ADDITIONAL_INFORMATION_LEN 255
|
||||
@@ -73,7 +94,7 @@ ED8(c_uint8_t ebi15:1;,
|
||||
* See subclause 10.5.1.3 in 3GPP TS 24.008 [13]
|
||||
* O TV 6 */
|
||||
typedef struct _nas_location_area_identification_t {
|
||||
plmn_id_t plmn_id;
|
||||
nas_plmn_id_t plmn_id;
|
||||
c_uint16_t lac;
|
||||
} __attribute__ ((packed)) nas_location_area_identification_t;
|
||||
|
||||
@@ -121,7 +142,7 @@ ED5(c_uint8_t spare:2;,
|
||||
c_uint8_t odd_even:1;,
|
||||
c_uint8_t type:3;)
|
||||
c_uint8_t mbms_servicec_id[3];
|
||||
plmn_id_t plmn_id;
|
||||
nas_plmn_id_t plmn_id;
|
||||
c_uint8_t mbms_session_identity;
|
||||
} __attribute__ ((packed)) nas_mobile_identity_tmgi_t;
|
||||
|
||||
@@ -187,7 +208,7 @@ typedef struct _nas_mobile_station_classmark_3_t {
|
||||
#define NAS_MAX_PLMN 15
|
||||
typedef struct _nas_plmn_list_t {
|
||||
c_uint8_t length;
|
||||
plmn_id_t plmn_id[NAS_MAX_PLMN];
|
||||
nas_plmn_id_t plmn_id[NAS_MAX_PLMN];
|
||||
} __attribute__ ((packed)) nas_plmn_list_t;
|
||||
|
||||
/* 9.9.2.10 Supported codec list
|
||||
@@ -415,7 +436,7 @@ typedef struct _nas_eps_mobile_identity_guti_t {
|
||||
ED3(c_uint8_t spare:4;,
|
||||
c_uint8_t odd_even:1;,
|
||||
c_uint8_t type:3;)
|
||||
plmn_id_t plmn_id;
|
||||
nas_plmn_id_t plmn_id;
|
||||
c_uint16_t mme_gid;
|
||||
c_uint8_t mme_code;
|
||||
c_uint32_t m_tmsi;
|
||||
@@ -715,8 +736,12 @@ typedef struct _nas_time_zone_and_time_t {
|
||||
c_uint8_t hour;
|
||||
c_uint8_t min;
|
||||
c_uint8_t sec;
|
||||
ED2(c_uint8_t sign:1;,
|
||||
c_uint8_t gmtoff:7;) /* quarters of an hour */
|
||||
/* The Time Zone indicates the difference, expressed in quarters of an hour,
|
||||
* between the local time and GMT. In the first of the two semi-octets,
|
||||
* the first bit (bit 3 of the seventh octet of
|
||||
* the TP-Service-Centre-Time-Stamp field) represents
|
||||
* the algebraic sign of this difference (0: positive, 1: negative). */
|
||||
c_uint8_t timezone;
|
||||
} nas_time_zone_and_time_t;
|
||||
|
||||
/* 9.9.3.31 TMSI status
|
||||
@@ -730,7 +755,10 @@ ED3(c_uint8_t type:4;,
|
||||
|
||||
/* 9.9.3.32 Tracking area identity
|
||||
* O TV 6 */
|
||||
typedef tai_t nas_tracking_area_identity_t;
|
||||
typedef struct _nas_tracking_area_identity_t {
|
||||
nas_plmn_id_t plmn_id;
|
||||
uint16_t tac;
|
||||
} __attribute__ ((packed)) nas_tracking_area_identity_t;
|
||||
|
||||
/* 9.9.3.33 Tracking area identity list
|
||||
* M LV 7-97 */
|
||||
@@ -743,6 +771,12 @@ typedef struct _tai0_list_t {
|
||||
ED3(c_uint8_t spare:1;,
|
||||
c_uint8_t type:2;,
|
||||
c_uint8_t num:5;)
|
||||
/*
|
||||
* Do not change 'plmn_id_t' to 'nas_plmn_id_t'.
|
||||
* Use 'plmn_id_t' for easy implementation.
|
||||
* nas_tai_list_build() changes to NAS format(nas_plmn_id_t)
|
||||
* and is sent to the UE.
|
||||
*/
|
||||
plmn_id_t plmn_id;
|
||||
c_uint16_t tac[MAX_NUM_OF_TAI];
|
||||
} __attribute__ ((packed)) tai[MAX_NUM_OF_TAI];
|
||||
@@ -752,6 +786,12 @@ typedef struct _tai2_list_t {
|
||||
ED3(c_uint8_t spare:1;,
|
||||
c_uint8_t type:2;,
|
||||
c_uint8_t num:5;)
|
||||
/*
|
||||
* Do not change 'tai_t' to 'nas_tracking_area_identity_t'.
|
||||
* Use 'tai_t' for easy implementation.
|
||||
* nas_tai_list_build() changes to NAS format(nas_tracking_area_identity_t)
|
||||
* and is sent to the UE.
|
||||
*/
|
||||
tai_t tai[MAX_NUM_OF_TAI];
|
||||
} __attribute__ ((packed)) tai2_list_t;
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ def output_header_to_file(f):
|
||||
|
||||
""")
|
||||
f.write("/*******************************************************************************\n")
|
||||
f.write(" * This file had been created by gtpv2c_tlv.py script v%s\n" % (version))
|
||||
f.write(" * This file had been created by nas_message.py script v%s\n" % (version))
|
||||
f.write(" * Please do not modify this file but regenerate it via script.\n")
|
||||
f.write(" * Created on: %s by %s\n * from %s\n" % (str(now), getpass.getuser(), filename))
|
||||
f.write(" ******************************************************************************/\n\n")
|
||||
|
||||
@@ -72,17 +72,17 @@ status_t app_did_initialize(void)
|
||||
void app_will_terminate(void)
|
||||
{
|
||||
app_logger_stop();
|
||||
}
|
||||
|
||||
void app_did_terminate(void)
|
||||
{
|
||||
if (context_self()->db_uri)
|
||||
{
|
||||
d_trace(1, "DB-Client try to terminate\n");
|
||||
context_db_final();
|
||||
d_trace(1, "DB-Client terminate...done\n");
|
||||
}
|
||||
}
|
||||
|
||||
void app_did_terminate(void)
|
||||
{
|
||||
app_logger_final();
|
||||
|
||||
context_final();
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
#include <yaml.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
yaml_document_t *document;
|
||||
yaml_node_t *node;
|
||||
|
||||
@@ -21,6 +21,7 @@ libmme_la_SOURCES = \
|
||||
esm_sm.c esm_handler.c esm_build.c \
|
||||
mme_gtp_path.c mme_s11_build.c mme_s11_handler.c \
|
||||
mme_sm.c mme_path.c \
|
||||
sbc_message.h sbc_handler.h sbc_handler.c \
|
||||
$(NULL)
|
||||
|
||||
if USRSCTP
|
||||
|
||||
@@ -278,13 +278,22 @@ status_t emm_build_security_mode_command(
|
||||
sizeof(replayed_ue_security_capabilities->uea) +
|
||||
sizeof(replayed_ue_security_capabilities->uia) +
|
||||
sizeof(replayed_ue_security_capabilities->gea);
|
||||
d_trace(5, " SEC[LEN:%d EEA:0x%x EIA:0x%x UEA:0x%x UIA:0x%x GEA:0x%x]\n",
|
||||
d_trace(5, " UE[LEN:%d EEA:0x%x EIA:0x%x UEA:0x%x UIA:0x%x GEA:0x%x]\n",
|
||||
replayed_ue_security_capabilities->length,
|
||||
replayed_ue_security_capabilities->eea,
|
||||
replayed_ue_security_capabilities->eia,
|
||||
replayed_ue_security_capabilities->uea,
|
||||
replayed_ue_security_capabilities->uia,
|
||||
replayed_ue_security_capabilities->gea);
|
||||
d_trace(5, " Selected[Integrity:0x%x Encrypt:0x%x]\n",
|
||||
mme_ue->selected_int_algorithm, mme_ue->selected_enc_algorithm);
|
||||
if (mme_ue->selected_int_algorithm == NAS_SECURITY_ALGORITHMS_EIA0)
|
||||
{
|
||||
d_fatal("Encrypt[0x%x] CAN BE skipped, "
|
||||
"but Integrity[0x%x] CANNOT BE skipped",
|
||||
mme_ue->selected_enc_algorithm, mme_ue->selected_int_algorithm);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
mme_kdf_nas(MME_KDF_NAS_INT_ALG, mme_ue->selected_int_algorithm,
|
||||
mme_ue->kasme, mme_ue->knas_int);
|
||||
|
||||
@@ -100,9 +100,8 @@ status_t emm_handle_attach_request(
|
||||
{
|
||||
nas_tracking_area_identity_t *last_visited_registered_tai =
|
||||
&attach_request->last_visited_registered_tai;
|
||||
|
||||
memcpy(&mme_ue->visited_plmn_id,
|
||||
&last_visited_registered_tai->plmn_id, PLMN_ID_LEN);
|
||||
nas_to_plmn_id(
|
||||
&mme_ue->visited_plmn_id, &last_visited_registered_tai->plmn_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -222,12 +221,16 @@ status_t emm_handle_attach_complete(
|
||||
universal_time_and_local_time_zone->min = NAS_TIME_TO_BCD(xt_gmt.tm_min);
|
||||
universal_time_and_local_time_zone->sec = NAS_TIME_TO_BCD(xt_gmt.tm_sec);
|
||||
if (xt_local.tm_gmtoff >= 0)
|
||||
universal_time_and_local_time_zone->sign = 0;
|
||||
{
|
||||
universal_time_and_local_time_zone->timezone =
|
||||
NAS_TIME_TO_BCD(xt_local.tm_gmtoff / 900);
|
||||
}
|
||||
else
|
||||
universal_time_and_local_time_zone->sign = 1;
|
||||
/* quarters of an hour */
|
||||
universal_time_and_local_time_zone->gmtoff =
|
||||
NAS_TIME_TO_BCD(xt_local.tm_gmtoff / 900);
|
||||
{
|
||||
universal_time_and_local_time_zone->timezone =
|
||||
NAS_TIME_TO_BCD((-xt_local.tm_gmtoff) / 900);
|
||||
universal_time_and_local_time_zone->timezone |= 0x08;
|
||||
}
|
||||
|
||||
emm_information->presencemask |=
|
||||
NAS_EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_PRESENT;
|
||||
@@ -460,9 +463,8 @@ status_t emm_handle_tau_request(
|
||||
{
|
||||
nas_tracking_area_identity_t *last_visited_registered_tai =
|
||||
&tau_request->last_visited_registered_tai;
|
||||
|
||||
memcpy(&mme_ue->visited_plmn_id,
|
||||
&last_visited_registered_tai->plmn_id, PLMN_ID_LEN);
|
||||
nas_to_plmn_id(
|
||||
&mme_ue->visited_plmn_id, &last_visited_registered_tai->plmn_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -403,10 +403,9 @@ void emm_state_authentication(fsm_t *s, event_t *e)
|
||||
d_trace(3, "[EMM] Authentication response\n");
|
||||
d_trace(5, " IMSI[%s]\n", mme_ue->imsi_bcd);
|
||||
|
||||
if (authentication_response_parameter->length !=
|
||||
mme_ue->xres_len ||
|
||||
memcmp(authentication_response_parameter->res,
|
||||
mme_ue->xres, mme_ue->xres_len) != 0)
|
||||
if (memcmp(authentication_response_parameter->res,
|
||||
mme_ue->xres,
|
||||
authentication_response_parameter->length) != 0)
|
||||
{
|
||||
rv = nas_send_authentication_reject(mme_ue);
|
||||
d_assert(rv == CORE_OK,, "nas send error");
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
static mme_context_t self;
|
||||
static fd_config_t g_fd_conf;
|
||||
|
||||
pool_declare(mme_sgw_pool, mme_sgw_t, MAX_NUM_OF_SGW);
|
||||
pool_declare(mme_pgw_pool, mme_pgw_t, MAX_NUM_OF_PGW);
|
||||
|
||||
index_declare(mme_enb_pool, mme_enb_t, MAX_NUM_OF_ENB);
|
||||
index_declare(mme_ue_pool, mme_ue_t, MAX_POOL_OF_UE);
|
||||
index_declare(enb_ue_pool, enb_ue_t, MAX_POOL_OF_UE);
|
||||
@@ -59,6 +62,9 @@ status_t mme_context_init()
|
||||
list_init(&self.sgw_list);
|
||||
list_init(&self.pgw_list);
|
||||
|
||||
pool_init(&mme_sgw_pool, MAX_NUM_OF_SGW);
|
||||
pool_init(&mme_pgw_pool, MAX_NUM_OF_PGW);
|
||||
|
||||
index_init(&mme_enb_pool, MAX_NUM_OF_ENB);
|
||||
|
||||
index_init(&mme_ue_pool, MAX_POOL_OF_UE);
|
||||
@@ -121,8 +127,12 @@ status_t mme_context_final()
|
||||
|
||||
index_final(&mme_enb_pool);
|
||||
|
||||
gtp_remove_all_nodes(&self.sgw_list);
|
||||
gtp_remove_all_nodes(&self.pgw_list);
|
||||
mme_sgw_remove_all();
|
||||
mme_pgw_remove_all();
|
||||
|
||||
pool_final(&mme_sgw_pool);
|
||||
pool_final(&mme_pgw_pool);
|
||||
|
||||
gtp_node_final();
|
||||
|
||||
sock_remove_all_nodes(&self.s1ap_list);
|
||||
@@ -1280,12 +1290,14 @@ status_t mme_context_parse_config()
|
||||
yaml_iter_recurse(&mme_iter, >pc_array);
|
||||
do
|
||||
{
|
||||
gtp_node_t *sgw = NULL;
|
||||
mme_sgw_t *sgw = NULL;
|
||||
c_sockaddr_t *list = NULL;
|
||||
int family = AF_UNSPEC;
|
||||
int i, num = 0;
|
||||
const char *hostname[MAX_NUM_OF_HOSTNAME];
|
||||
c_uint16_t port = self.gtpc_port;
|
||||
c_uint16_t tac[MAX_NUM_OF_TAI] = {0,};
|
||||
c_uint8_t num_of_tac = 0;
|
||||
|
||||
if (yaml_iter_type(>pc_array) == YAML_MAPPING_NODE)
|
||||
{
|
||||
@@ -1356,6 +1368,36 @@ status_t mme_context_parse_config()
|
||||
const char *v = yaml_iter_value(>pc_iter);
|
||||
if (v) port = atoi(v);
|
||||
}
|
||||
else if (!strcmp(gtpc_key, "tac"))
|
||||
{
|
||||
yaml_iter_t tac_iter;
|
||||
yaml_iter_recurse(>pc_iter, &tac_iter);
|
||||
d_assert(yaml_iter_type(&tac_iter) !=
|
||||
YAML_MAPPING_NODE, return CORE_ERROR,);
|
||||
|
||||
do
|
||||
{
|
||||
const char *v = NULL;
|
||||
|
||||
d_assert(num_of_tac <=
|
||||
MAX_NUM_OF_TAI, return CORE_ERROR,);
|
||||
if (yaml_iter_type(&tac_iter) ==
|
||||
YAML_SEQUENCE_NODE)
|
||||
{
|
||||
if (!yaml_iter_next(&tac_iter))
|
||||
break;
|
||||
}
|
||||
|
||||
v = yaml_iter_value(&tac_iter);
|
||||
if (v)
|
||||
{
|
||||
tac[num_of_tac] = atoi(v);
|
||||
num_of_tac++;
|
||||
}
|
||||
} while(
|
||||
yaml_iter_type(&tac_iter) ==
|
||||
YAML_SEQUENCE_NODE);
|
||||
}
|
||||
else
|
||||
d_warn("unknown key `%s`", gtpc_key);
|
||||
}
|
||||
@@ -1368,16 +1410,33 @@ status_t mme_context_parse_config()
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
}
|
||||
|
||||
rv = gtp_add_node(&self.sgw_list, &sgw, list,
|
||||
sgw = mme_sgw_add(list,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
context_self()->parameter.prefer_ipv4);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
d_assert(sgw, return CORE_ERROR,);
|
||||
|
||||
sgw->num_of_tac = num_of_tac;
|
||||
if (num_of_tac != 0)
|
||||
memcpy(sgw->tac, tac, sizeof(sgw->tac));
|
||||
|
||||
core_freeaddrinfo(list);
|
||||
|
||||
} while(yaml_iter_type(>pc_array) == YAML_SEQUENCE_NODE);
|
||||
}
|
||||
else if(!strcmp(mme_key, "selection_mode"))
|
||||
{
|
||||
const char *selection_mode =
|
||||
yaml_iter_value(&mme_iter);
|
||||
|
||||
if (!strcmp(selection_mode, "rr"))
|
||||
self.sgw_selection = SGW_SELECT_RR;
|
||||
else if (!strcmp(selection_mode, "tac"))
|
||||
self.sgw_selection = SGW_SELECT_TAC;
|
||||
else
|
||||
d_warn("unknown sgw_selection mode `%s`",
|
||||
selection_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(root_key, "pgw"))
|
||||
@@ -1394,7 +1453,7 @@ status_t mme_context_parse_config()
|
||||
yaml_iter_recurse(&mme_iter, >pc_array);
|
||||
do
|
||||
{
|
||||
gtp_node_t *pgw = NULL;
|
||||
mme_pgw_t *pgw = NULL;
|
||||
c_sockaddr_t *list = NULL;
|
||||
int family = AF_UNSPEC;
|
||||
int i, num = 0;
|
||||
@@ -1482,11 +1541,11 @@ status_t mme_context_parse_config()
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
}
|
||||
|
||||
rv = gtp_add_node(&self.pgw_list, &pgw, list,
|
||||
pgw = mme_pgw_add(list,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
context_self()->parameter.prefer_ipv4);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
d_assert(pgw, return CORE_ERROR,);
|
||||
|
||||
core_freeaddrinfo(list);
|
||||
|
||||
@@ -1595,6 +1654,123 @@ status_t mme_context_setup_trace_module()
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
mme_sgw_t *mme_sgw_add(
|
||||
c_sockaddr_t *all_list, int no_ipv4, int no_ipv6, int prefer_ipv4)
|
||||
{
|
||||
status_t rv;
|
||||
mme_sgw_t *sgw = NULL;
|
||||
|
||||
d_assert(all_list, return NULL, "Null param");
|
||||
|
||||
pool_alloc_node(&mme_sgw_pool, &sgw);
|
||||
d_assert(sgw, return NULL, "Null param");
|
||||
memset(sgw, 0, sizeof *sgw);
|
||||
|
||||
rv = gtp_create_node(&sgw->gnode, all_list, no_ipv4, no_ipv6, prefer_ipv4);
|
||||
d_assert(rv == CORE_OK, return NULL,);
|
||||
if (sgw->gnode == NULL)
|
||||
{
|
||||
d_error("Invalid Parameter : "
|
||||
"no_ipv4[%d], no_ipv6[%d], prefer_ipv4[%d]",
|
||||
no_ipv4, no_ipv6, prefer_ipv4);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_append(&self.sgw_list, sgw);
|
||||
|
||||
return sgw;
|
||||
}
|
||||
|
||||
status_t mme_sgw_remove(mme_sgw_t *sgw)
|
||||
{
|
||||
status_t rv;
|
||||
d_assert(sgw, return CORE_ERROR, "Null param");
|
||||
|
||||
list_remove(&self.sgw_list, sgw);
|
||||
|
||||
rv = gtp_delete_node(sgw->gnode);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
pool_free_node(&mme_sgw_pool, sgw);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t mme_sgw_remove_all()
|
||||
{
|
||||
mme_sgw_t *sgw = NULL, *next_sgw = NULL;
|
||||
|
||||
sgw = list_first(&self.sgw_list);
|
||||
while (sgw)
|
||||
{
|
||||
next_sgw = list_next(sgw);
|
||||
|
||||
mme_sgw_remove(sgw);
|
||||
|
||||
sgw = next_sgw;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
mme_pgw_t *mme_pgw_add(
|
||||
c_sockaddr_t *all_list, int no_ipv4, int no_ipv6, int prefer_ipv4)
|
||||
{
|
||||
status_t rv;
|
||||
mme_pgw_t *pgw = NULL;
|
||||
|
||||
d_assert(all_list, return NULL, "Null param");
|
||||
|
||||
pool_alloc_node(&mme_pgw_pool, &pgw);
|
||||
d_assert(pgw, return NULL, "Null param");
|
||||
|
||||
rv = gtp_create_node(&pgw->gnode, all_list, no_ipv4, no_ipv6, prefer_ipv4);
|
||||
d_assert(rv == CORE_OK, return NULL,);
|
||||
if (pgw->gnode == NULL)
|
||||
{
|
||||
d_error("Invalid Parameter : "
|
||||
"no_ipv4[%d], no_ipv6[%d], prefer_ipv4[%d]",
|
||||
no_ipv4, no_ipv6, prefer_ipv4);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_append(&self.pgw_list, pgw);
|
||||
|
||||
return pgw;
|
||||
}
|
||||
|
||||
status_t mme_pgw_remove(mme_pgw_t *pgw)
|
||||
{
|
||||
status_t rv;
|
||||
d_assert(pgw, return CORE_ERROR, "Null param");
|
||||
|
||||
list_remove(&self.pgw_list, pgw);
|
||||
|
||||
rv = gtp_delete_node(pgw->gnode);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
pool_free_node(&mme_pgw_pool, pgw);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t mme_pgw_remove_all()
|
||||
{
|
||||
mme_pgw_t *pgw = NULL, *next_pgw = NULL;
|
||||
|
||||
pgw = list_first(&self.pgw_list);
|
||||
while (pgw)
|
||||
{
|
||||
next_pgw = list_next(pgw);
|
||||
|
||||
mme_pgw_remove(pgw);
|
||||
|
||||
pgw = next_pgw;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
mme_enb_t* mme_enb_add(sock_id sock, c_sockaddr_t *addr)
|
||||
{
|
||||
mme_enb_t *enb = NULL;
|
||||
@@ -1637,8 +1813,7 @@ status_t mme_enb_remove(mme_enb_t *enb)
|
||||
|
||||
hash_set(self.enb_sock_hash, &enb->sock, sizeof(enb->sock), NULL);
|
||||
hash_set(self.enb_addr_hash, enb->addr, sizeof(c_sockaddr_t), NULL);
|
||||
if (enb->enb_id)
|
||||
hash_set(self.enb_id_hash, &enb->enb_id, sizeof(enb->enb_id), NULL);
|
||||
hash_set(self.enb_id_hash, &enb->enb_id, sizeof(enb->enb_id), NULL);
|
||||
|
||||
enb_ue_remove_in_enb(enb);
|
||||
|
||||
@@ -1692,14 +1867,12 @@ mme_enb_t* mme_enb_find_by_addr(c_sockaddr_t *addr)
|
||||
|
||||
mme_enb_t* mme_enb_find_by_enb_id(c_uint32_t enb_id)
|
||||
{
|
||||
d_assert(enb_id, return NULL,"Invalid param");
|
||||
return (mme_enb_t *)hash_get(self.enb_id_hash, &enb_id, sizeof(enb_id));
|
||||
}
|
||||
|
||||
status_t mme_enb_set_enb_id(mme_enb_t *enb, c_uint32_t enb_id)
|
||||
{
|
||||
d_assert(enb, return CORE_ERROR, "Invalid param");
|
||||
d_assert(enb_id, return CORE_ERROR, "Invalid param");
|
||||
|
||||
enb->enb_id = enb_id;
|
||||
hash_set(self.enb_id_hash, &enb->enb_id, sizeof(enb->enb_id), enb);
|
||||
@@ -1946,13 +2119,39 @@ mme_ue_t* mme_ue_add(enb_ue_t *enb_ue)
|
||||
/* Create New GUTI */
|
||||
mme_ue_new_guti(mme_ue);
|
||||
|
||||
/* Setup SGW with round-robin manner */
|
||||
if (mme_self()->sgw == NULL)
|
||||
if (mme_self()->sgw_selection == SGW_SELECT_RR)
|
||||
{
|
||||
/* Setup SGW with round-robin manner */
|
||||
if (mme_self()->sgw == NULL)
|
||||
mme_self()->sgw = list_first(&mme_self()->sgw_list);
|
||||
|
||||
d_assert(mme_self()->sgw, return NULL,);
|
||||
SETUP_GTP_NODE(mme_ue, mme_self()->sgw->gnode);
|
||||
|
||||
mme_self()->sgw = list_next(mme_self()->sgw);
|
||||
}
|
||||
else if (mme_self()->sgw_selection == SGW_SELECT_TAC)
|
||||
{
|
||||
/* Select SGW by eNB TAC */
|
||||
int i, found = 0;
|
||||
|
||||
mme_self()->sgw = list_first(&mme_self()->sgw_list);
|
||||
while(mme_self()->sgw && !found)
|
||||
{
|
||||
for (i = 0; i < mme_self()->sgw->num_of_tac && !found; i++)
|
||||
found = mme_self()->sgw->tac[i] == enb_ue->nas.tai.tac ? 1: 0;
|
||||
|
||||
SETUP_GTP_NODE(mme_ue, mme_self()->sgw);
|
||||
if (!found)
|
||||
mme_self()->sgw = list_next(mme_self()->sgw);
|
||||
}
|
||||
|
||||
mme_self()->sgw = list_next(mme_self()->sgw);
|
||||
d_assert(mme_self()->sgw, return NULL,);
|
||||
SETUP_GTP_NODE(mme_ue, mme_self()->sgw->gnode);
|
||||
}
|
||||
else
|
||||
d_assert(0, return NULL, "Invalid Selection Mode: %d",
|
||||
mme_self()->sgw_selection);
|
||||
|
||||
|
||||
/* Create paging retry timer */
|
||||
mme_ue->t3413 = timer_create(&self.tm_service, MME_EVT_EMM_T3413,
|
||||
|
||||
@@ -34,6 +34,9 @@ extern "C" {
|
||||
|
||||
#define MAX_NUM_OF_BPLMN 6
|
||||
|
||||
typedef struct _mme_sgw_t mme_sgw_t;
|
||||
typedef struct _mme_pgw_t mme_pgw_t;
|
||||
|
||||
typedef struct _enb_ue_t enb_ue_t;
|
||||
typedef struct _mme_ue_t mme_ue_t;
|
||||
|
||||
@@ -44,6 +47,11 @@ typedef struct _fd_config_t fd_config_t;
|
||||
|
||||
typedef c_uint32_t mme_m_tmsi_t;
|
||||
|
||||
typedef enum {
|
||||
SGW_SELECT_RR = 0, /* Default SGW Selection Method */
|
||||
SGW_SELECT_TAC,
|
||||
} sgw_select_e;
|
||||
|
||||
typedef struct _served_gummei {
|
||||
c_uint32_t num_of_plmn_id;
|
||||
plmn_id_t plmn_id[MAX_PLMN_ID];
|
||||
@@ -72,7 +80,7 @@ typedef struct _mme_context_t {
|
||||
c_sockaddr_t *gtpc_addr6; /* MME GTPC IPv6 Address */
|
||||
|
||||
list_t sgw_list; /* SGW GTPC Client List */
|
||||
gtp_node_t *sgw; /* Iterator for SGW round-robin */
|
||||
mme_sgw_t *sgw; /* Iterator for SGW round-robin */
|
||||
|
||||
list_t pgw_list; /* PGW GTPC Client List */
|
||||
c_sockaddr_t *pgw_addr; /* First IPv4 Address Selected */
|
||||
@@ -137,9 +145,27 @@ typedef struct _mme_context_t {
|
||||
/* Network Name */
|
||||
nas_network_name_t short_name; /* Network short name */
|
||||
nas_network_name_t full_name; /* Network Full Name */
|
||||
|
||||
/* SGW Selection */
|
||||
sgw_select_e sgw_selection;
|
||||
|
||||
} mme_context_t;
|
||||
|
||||
typedef struct _mme_sgw_t {
|
||||
lnode_t node;
|
||||
|
||||
c_uint16_t tac[MAX_NUM_OF_TAI];
|
||||
c_uint8_t num_of_tac;
|
||||
|
||||
gtp_node_t *gnode;
|
||||
} mme_sgw_t;
|
||||
|
||||
typedef struct _mme_pgw_t {
|
||||
lnode_t node;
|
||||
|
||||
gtp_node_t *gnode;
|
||||
} mme_pgw_t;
|
||||
|
||||
typedef struct _mme_enb_t {
|
||||
index_t index; /* An index of this node */
|
||||
fsm_t sm; /* A state machine */
|
||||
@@ -509,6 +535,16 @@ CORE_DECLARE(mme_context_t*) mme_self(void);
|
||||
CORE_DECLARE(status_t) mme_context_parse_config(void);
|
||||
CORE_DECLARE(status_t) mme_context_setup_trace_module(void);
|
||||
|
||||
CORE_DECLARE(mme_sgw_t*) mme_sgw_add(
|
||||
c_sockaddr_t *all_list, int no_ipv4, int no_ipv6, int prefer_ipv4);
|
||||
CORE_DECLARE(status_t ) mme_sgw_remove(mme_sgw_t *sgw);
|
||||
CORE_DECLARE(status_t ) mme_sgw_remove_all();
|
||||
|
||||
CORE_DECLARE(mme_pgw_t*) mme_pgw_add(
|
||||
c_sockaddr_t *all_list, int no_ipv4, int no_ipv6, int prefer_ipv4);
|
||||
CORE_DECLARE(status_t ) mme_pgw_remove(mme_pgw_t *pgw);
|
||||
CORE_DECLARE(status_t ) mme_pgw_remove_all();
|
||||
|
||||
CORE_DECLARE(mme_enb_t*) mme_enb_add(sock_id sock, c_sockaddr_t *addr);
|
||||
CORE_DECLARE(status_t) mme_enb_remove(mme_enb_t *enb);
|
||||
CORE_DECLARE(status_t) mme_enb_remove_all(void);
|
||||
|
||||
@@ -43,14 +43,15 @@ static int _gtpv2_c_recv_cb(sock_id sock, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static c_sockaddr_t *gtp_addr_find_by_family(list_t *list, int family)
|
||||
static c_sockaddr_t *pgw_addr_find_by_family(list_t *list, int family)
|
||||
{
|
||||
gtp_node_t *gnode = NULL;
|
||||
mme_pgw_t *pgw = NULL;
|
||||
d_assert(list, return NULL,);
|
||||
|
||||
for (gnode = list_first(list); gnode; gnode = list_next(gnode))
|
||||
for (pgw = list_first(list); pgw; pgw = list_next(pgw))
|
||||
{
|
||||
c_sockaddr_t *addr = gnode->sa_list;
|
||||
d_assert(pgw->gnode, return NULL,);
|
||||
c_sockaddr_t *addr = pgw->gnode->sa_list;
|
||||
while(addr)
|
||||
{
|
||||
if (addr->c_sa_family == family)
|
||||
@@ -67,7 +68,7 @@ static c_sockaddr_t *gtp_addr_find_by_family(list_t *list, int family)
|
||||
status_t mme_gtp_open()
|
||||
{
|
||||
status_t rv;
|
||||
gtp_node_t *gnode = NULL;
|
||||
mme_sgw_t *sgw = NULL;
|
||||
|
||||
rv = gtp_server_list(&mme_self()->gtpc_list, _gtpv2_c_recv_cb);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
@@ -82,17 +83,16 @@ status_t mme_gtp_open()
|
||||
d_assert(mme_self()->gtpc_addr || mme_self()->gtpc_addr6,
|
||||
return CORE_ERROR, "No GTP Server");
|
||||
|
||||
mme_self()->pgw_addr = gtp_addr_find_by_family(
|
||||
mme_self()->pgw_addr = pgw_addr_find_by_family(
|
||||
&mme_self()->pgw_list, AF_INET);
|
||||
mme_self()->pgw_addr6 = gtp_addr_find_by_family(
|
||||
mme_self()->pgw_addr6 = pgw_addr_find_by_family(
|
||||
&mme_self()->pgw_list, AF_INET6);
|
||||
d_assert(mme_self()->pgw_addr || mme_self()->pgw_addr6,
|
||||
return CORE_ERROR,);
|
||||
|
||||
for (gnode = list_first(&mme_self()->sgw_list);
|
||||
gnode; gnode = list_next(gnode))
|
||||
for (sgw = list_first(&mme_self()->sgw_list); sgw; sgw = list_next(sgw))
|
||||
{
|
||||
rv = gtp_client(gnode);
|
||||
rv = gtp_client(sgw->gnode);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,11 +206,15 @@ status_t mme_s11_build_create_session_request(
|
||||
memset(&ue_timezone, 0, sizeof(ue_timezone));
|
||||
time_exp_lt(&time_exp, time_now());
|
||||
if (time_exp.tm_gmtoff >= 0)
|
||||
ue_timezone.sign = 0;
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
}
|
||||
else
|
||||
ue_timezone.sign = 1;
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD((-time_exp.tm_gmtoff) / 900);
|
||||
ue_timezone.timezone |= 0x08;
|
||||
}
|
||||
/* quarters of an hour */
|
||||
ue_timezone.gmtoff = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
ue_timezone.daylight_saving_time =
|
||||
GTP_UE_TIME_ZONE_NO_ADJUSTMENT_FOR_DAYLIGHT_SAVING_TIME;
|
||||
req->ue_time_zone.presence = 1;
|
||||
@@ -427,11 +431,14 @@ status_t mme_s11_build_create_bearer_response(
|
||||
memset(&ue_timezone, 0, sizeof(ue_timezone));
|
||||
time_exp_lt(&time_exp, time_now());
|
||||
if (time_exp.tm_gmtoff >= 0)
|
||||
ue_timezone.sign = 0;
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
}
|
||||
else
|
||||
ue_timezone.sign = 1;
|
||||
/* quarters of an hour */
|
||||
ue_timezone.gmtoff = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD((-time_exp.tm_gmtoff) / 900);
|
||||
ue_timezone.timezone |= 0x08;
|
||||
}
|
||||
ue_timezone.daylight_saving_time =
|
||||
GTP_UE_TIME_ZONE_NO_ADJUSTMENT_FOR_DAYLIGHT_SAVING_TIME;
|
||||
rsp->ue_time_zone.presence = 1;
|
||||
@@ -504,11 +511,14 @@ status_t mme_s11_build_update_bearer_response(
|
||||
memset(&ue_timezone, 0, sizeof(ue_timezone));
|
||||
time_exp_lt(&time_exp, time_now());
|
||||
if (time_exp.tm_gmtoff >= 0)
|
||||
ue_timezone.sign = 0;
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
}
|
||||
else
|
||||
ue_timezone.sign = 1;
|
||||
/* quarters of an hour */
|
||||
ue_timezone.gmtoff = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD((-time_exp.tm_gmtoff) / 900);
|
||||
ue_timezone.timezone |= 0x08;
|
||||
}
|
||||
ue_timezone.daylight_saving_time =
|
||||
GTP_UE_TIME_ZONE_NO_ADJUSTMENT_FOR_DAYLIGHT_SAVING_TIME;
|
||||
rsp->ue_time_zone.presence = 1;
|
||||
@@ -581,11 +591,14 @@ status_t mme_s11_build_delete_bearer_response(
|
||||
memset(&ue_timezone, 0, sizeof(ue_timezone));
|
||||
time_exp_lt(&time_exp, time_now());
|
||||
if (time_exp.tm_gmtoff >= 0)
|
||||
ue_timezone.sign = 0;
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
}
|
||||
else
|
||||
ue_timezone.sign = 1;
|
||||
/* quarters of an hour */
|
||||
ue_timezone.gmtoff = GTP_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
||||
{
|
||||
ue_timezone.timezone = GTP_TIME_TO_BCD((-time_exp.tm_gmtoff) / 900);
|
||||
ue_timezone.timezone |= 0x08;
|
||||
}
|
||||
ue_timezone.daylight_saving_time =
|
||||
GTP_UE_TIME_ZONE_NO_ADJUSTMENT_FOR_DAYLIGHT_SAVING_TIME;
|
||||
rsp->ue_time_zone.presence = 1;
|
||||
|
||||
@@ -1709,6 +1709,8 @@ status_t s1ap_build_handover_request(
|
||||
subscription_data = &mme_ue->subscription_data;
|
||||
d_assert(subscription_data, return CORE_ERROR, "Null param");
|
||||
|
||||
d_trace(3, "[MME] Handover request\n");
|
||||
|
||||
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
|
||||
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage =
|
||||
@@ -2287,7 +2289,7 @@ status_t s1ap_build_s1_reset_ack(
|
||||
|
||||
S1AP_ResetAcknowledgeIEs_t *ie = NULL;
|
||||
|
||||
d_trace(3, "[MME] ResetAcknowledge\n");
|
||||
d_trace(3, "[MME] Reset acknowledge\n");
|
||||
|
||||
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
|
||||
pdu.present = S1AP_S1AP_PDU_PR_successfulOutcome;
|
||||
@@ -2384,3 +2386,226 @@ status_t s1ap_build_s1_reset_ack(
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t s1ap_build_write_replace_warning_request(
|
||||
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws)
|
||||
{
|
||||
status_t rv;
|
||||
|
||||
S1AP_S1AP_PDU_t pdu;
|
||||
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
||||
S1AP_WriteReplaceWarningRequest_t *WriteReplaceWarningRequest = NULL;
|
||||
|
||||
S1AP_WriteReplaceWarningRequestIEs_t *ie = NULL;
|
||||
S1AP_MessageIdentifier_t *MessageIdentifier = NULL;
|
||||
S1AP_SerialNumber_t *SerialNumber = NULL;
|
||||
S1AP_RepetitionPeriod_t *RepetitionPeriod = NULL;
|
||||
S1AP_NumberofBroadcastRequest_t *NumberofBroadcastRequest = NULL;
|
||||
S1AP_DataCodingScheme_t *DataCodingScheme = NULL;
|
||||
S1AP_WarningMessageContents_t *WarningMessageContents = NULL;
|
||||
|
||||
d_trace(3, "[MME] Write-replace warning request\n");
|
||||
|
||||
d_assert(sbc_pws, return CORE_ERROR,);
|
||||
|
||||
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
|
||||
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage =
|
||||
core_calloc(1, sizeof(S1AP_InitiatingMessage_t));
|
||||
|
||||
initiatingMessage = pdu.choice.initiatingMessage;
|
||||
initiatingMessage->procedureCode = S1AP_ProcedureCode_id_WriteReplaceWarning;
|
||||
initiatingMessage->criticality = S1AP_Criticality_reject;
|
||||
initiatingMessage->value.present =
|
||||
S1AP_InitiatingMessage__value_PR_WriteReplaceWarningRequest;
|
||||
|
||||
WriteReplaceWarningRequest = &initiatingMessage->value.choice.WriteReplaceWarningRequest;
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_MessageIdentifier;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_MessageIdentifier;
|
||||
|
||||
MessageIdentifier = &ie->value.choice.MessageIdentifier;
|
||||
|
||||
MessageIdentifier->size = (16 / 8);
|
||||
MessageIdentifier->buf =
|
||||
core_calloc(MessageIdentifier->size, sizeof(c_uint8_t));
|
||||
MessageIdentifier->bits_unused = 0;
|
||||
MessageIdentifier->buf[0] = (sbc_pws->message_id >> 8) & 0xFF;
|
||||
MessageIdentifier->buf[1] = sbc_pws->message_id & 0xFF;
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_SerialNumber;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_SerialNumber;
|
||||
|
||||
SerialNumber = &ie->value.choice.SerialNumber;
|
||||
|
||||
SerialNumber->size = (16 / 8);
|
||||
SerialNumber->buf =
|
||||
core_calloc(SerialNumber->size, sizeof(c_uint8_t));
|
||||
SerialNumber->bits_unused = 0;
|
||||
SerialNumber->buf[0] = (sbc_pws->serial_number >> 8) & 0xFF;
|
||||
SerialNumber->buf[1] = sbc_pws->serial_number & 0xFF;
|
||||
|
||||
/* TODO: optional Warning Area List */
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_RepetitionPeriod;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_RepetitionPeriod;
|
||||
|
||||
RepetitionPeriod = &ie->value.choice.RepetitionPeriod;
|
||||
|
||||
*RepetitionPeriod = sbc_pws->repetition_period;
|
||||
|
||||
/* TODO: optional Extended Repetition Period */
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_NumberofBroadcastRequest;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_NumberofBroadcastRequest;
|
||||
|
||||
NumberofBroadcastRequest = &ie->value.choice.NumberofBroadcastRequest;
|
||||
|
||||
*NumberofBroadcastRequest = sbc_pws->number_of_broadcast;
|
||||
|
||||
/* TODO: optional Warnging Type */
|
||||
|
||||
/* TODO: optional Warning Security Information */
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_DataCodingScheme;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_DataCodingScheme;
|
||||
|
||||
DataCodingScheme = &ie->value.choice.DataCodingScheme;
|
||||
|
||||
DataCodingScheme->size = (8 / 8);
|
||||
DataCodingScheme->buf =
|
||||
core_calloc(DataCodingScheme->size, sizeof(c_uint8_t));
|
||||
DataCodingScheme->bits_unused = 0;
|
||||
DataCodingScheme->buf[0] = sbc_pws->data_coding_scheme & 0xFF;
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_WarningMessageContents;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_WarningMessageContents;
|
||||
|
||||
WarningMessageContents = &ie->value.choice.WarningMessageContents;
|
||||
|
||||
WarningMessageContents->size = sbc_pws->message_length;;
|
||||
WarningMessageContents->buf =
|
||||
core_calloc(WarningMessageContents->size, sizeof(c_uint8_t));
|
||||
memcpy(WarningMessageContents->buf, sbc_pws->message_contents, WarningMessageContents->size);
|
||||
|
||||
/* TODO: optional Concurrent Warning Message Indicator */
|
||||
|
||||
d_trace(5, " Message[%02x,%02x] Serial[%02x,%02x] Repetition[%d] NumBroadcast[%d]\n",
|
||||
MessageIdentifier->buf[0], MessageIdentifier->buf[1], SerialNumber->buf[0],
|
||||
SerialNumber->buf[1], *RepetitionPeriod, *NumberofBroadcastRequest);
|
||||
|
||||
rv = s1ap_encode_pdu(s1apbuf, &pdu);
|
||||
s1ap_free_pdu(&pdu);
|
||||
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("s1ap_encode_pdu() failed");
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t s1ap_build_kill_request(
|
||||
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws)
|
||||
{
|
||||
status_t rv;
|
||||
|
||||
S1AP_S1AP_PDU_t pdu;
|
||||
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
||||
S1AP_KillRequest_t *KillRequest = NULL;
|
||||
|
||||
S1AP_KillRequestIEs_t *ie = NULL;
|
||||
S1AP_MessageIdentifier_t *MessageIdentifier = NULL;
|
||||
S1AP_SerialNumber_t *SerialNumber = NULL;
|
||||
|
||||
d_trace(3, "[MME] Kill request\n");
|
||||
|
||||
d_assert(sbc_pws, return CORE_ERROR,);
|
||||
|
||||
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
|
||||
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage =
|
||||
core_calloc(1, sizeof(S1AP_InitiatingMessage_t));
|
||||
|
||||
initiatingMessage = pdu.choice.initiatingMessage;
|
||||
initiatingMessage->procedureCode = S1AP_ProcedureCode_id_Kill;
|
||||
initiatingMessage->criticality = S1AP_Criticality_reject;
|
||||
initiatingMessage->value.present =
|
||||
S1AP_InitiatingMessage__value_PR_KillRequest;
|
||||
|
||||
KillRequest = &initiatingMessage->value.choice.KillRequest;
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_KillRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&KillRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_MessageIdentifier;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_KillRequestIEs__value_PR_MessageIdentifier;
|
||||
|
||||
MessageIdentifier = &ie->value.choice.MessageIdentifier;
|
||||
|
||||
MessageIdentifier->size = (16 / 8);
|
||||
MessageIdentifier->buf =
|
||||
core_calloc(MessageIdentifier->size, sizeof(c_uint8_t));
|
||||
MessageIdentifier->bits_unused = 0;
|
||||
MessageIdentifier->buf[0] = (sbc_pws->message_id >> 8) & 0xFF;
|
||||
MessageIdentifier->buf[1] = sbc_pws->message_id & 0xFF;
|
||||
|
||||
ie = core_calloc(1, sizeof(S1AP_KillRequestIEs_t));
|
||||
ASN_SEQUENCE_ADD(&KillRequest->protocolIEs, ie);
|
||||
|
||||
ie->id = S1AP_ProtocolIE_ID_id_SerialNumber;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_KillRequestIEs__value_PR_SerialNumber;
|
||||
|
||||
SerialNumber = &ie->value.choice.SerialNumber;
|
||||
|
||||
SerialNumber->size = (16 / 8);
|
||||
SerialNumber->buf =
|
||||
core_calloc(SerialNumber->size, sizeof(c_uint8_t));
|
||||
SerialNumber->bits_unused = 0;
|
||||
SerialNumber->buf[0] = (sbc_pws->serial_number >> 8) & 0xFF;
|
||||
SerialNumber->buf[1] = sbc_pws->serial_number & 0xFF;
|
||||
|
||||
/* TODO: optional Warning Area List */
|
||||
|
||||
d_trace(5, " Message[%02x,%02x] Serial[%02x,%02x]\n",
|
||||
MessageIdentifier->buf[0], MessageIdentifier->buf[1],
|
||||
SerialNumber->buf[0], SerialNumber->buf[1]);
|
||||
|
||||
rv = s1ap_encode_pdu(s1apbuf, &pdu);
|
||||
s1ap_free_pdu(&pdu);
|
||||
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("s1ap_encode_pdu() failed");
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "s1ap/s1ap_message.h"
|
||||
#include "mme_context.h"
|
||||
|
||||
#include "sbc_message.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@@ -78,6 +80,12 @@ CORE_DECLARE(status_t) s1ap_build_s1_reset_ack(
|
||||
pkbuf_t **s1apbuf,
|
||||
S1AP_UE_associatedLogicalS1_ConnectionListRes_t *partOfS1_Interface);
|
||||
|
||||
CORE_DECLARE(status_t) s1ap_build_write_replace_warning_request(
|
||||
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws);
|
||||
|
||||
CORE_DECLARE(status_t) s1ap_build_kill_request(
|
||||
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -833,6 +833,7 @@ void s1ap_handle_ue_context_release_request(
|
||||
break;
|
||||
case S1AP_Cause_PR_nas:
|
||||
d_warn("NAS-Cause[%d]", Cause->choice.nas);
|
||||
break;
|
||||
default:
|
||||
d_warn("Invalid cause group[%d]", Cause->present);
|
||||
break;
|
||||
@@ -2106,3 +2107,52 @@ void s1ap_handle_s1_reset(
|
||||
d_assert(rv == CORE_OK,,);
|
||||
}
|
||||
|
||||
void s1ap_handle_write_replace_warning_response(
|
||||
mme_enb_t *enb, s1ap_message_t *message)
|
||||
{
|
||||
char buf[CORE_ADDRSTRLEN];
|
||||
|
||||
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
|
||||
S1AP_WriteReplaceWarningResponse_t *WriteReplaceWarningResponse = NULL;
|
||||
|
||||
d_assert(enb, return,);
|
||||
d_assert(enb->sock, return,);
|
||||
|
||||
d_assert(message, return,);
|
||||
successfulOutcome = message->choice.successfulOutcome;
|
||||
d_assert(successfulOutcome, return,);
|
||||
WriteReplaceWarningResponse =
|
||||
&successfulOutcome->value.choice.WriteReplaceWarningResponse;
|
||||
d_assert(WriteReplaceWarningResponse, return,);
|
||||
|
||||
d_trace(3, "[MME] Write replace warning response\n");
|
||||
|
||||
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
||||
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
||||
|
||||
}
|
||||
|
||||
void s1ap_handle_kill_response(
|
||||
mme_enb_t *enb, s1ap_message_t *message)
|
||||
{
|
||||
char buf[CORE_ADDRSTRLEN];
|
||||
|
||||
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
|
||||
S1AP_KillResponse_t *KillResponse = NULL;
|
||||
|
||||
d_assert(enb, return,);
|
||||
d_assert(enb->sock, return,);
|
||||
|
||||
d_assert(message, return,);
|
||||
successfulOutcome = message->choice.successfulOutcome;
|
||||
d_assert(successfulOutcome, return,);
|
||||
KillResponse =
|
||||
&successfulOutcome->value.choice.KillResponse;
|
||||
d_assert(KillResponse, return,);
|
||||
|
||||
d_trace(3, "[MME] Kill response\n");
|
||||
|
||||
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
||||
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ CORE_DECLARE(void) s1ap_handle_handover_notification(
|
||||
|
||||
CORE_DECLARE(void) s1ap_handle_s1_reset(
|
||||
mme_enb_t *enb, s1ap_message_t *message);
|
||||
|
||||
CORE_DECLARE(void) s1ap_handle_write_replace_warning_response(
|
||||
mme_enb_t *enb, s1ap_message_t *message);
|
||||
CORE_DECLARE(void) s1ap_handle_kill_response(
|
||||
mme_enb_t *enb, s1ap_message_t *message);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -179,6 +179,16 @@ void s1ap_state_operational(fsm_t *s, event_t *e)
|
||||
s1ap_handle_handover_request_ack(enb, pdu);
|
||||
break;
|
||||
}
|
||||
case S1AP_ProcedureCode_id_WriteReplaceWarning:
|
||||
{
|
||||
s1ap_handle_write_replace_warning_response(enb, pdu);
|
||||
break;
|
||||
}
|
||||
case S1AP_ProcedureCode_id_Kill:
|
||||
{
|
||||
s1ap_handle_kill_response(enb, pdu);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
d_warn("Not implemented(choice:%d, proc:%d)",
|
||||
|
||||
104
src/mme/sbc_handler.c
Normal file
104
src/mme/sbc_handler.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#define TRACE_MODULE _sbc_handler
|
||||
|
||||
#include "core_debug.h"
|
||||
|
||||
#include "mme_context.h"
|
||||
#include "s1ap_path.h"
|
||||
#include "s1ap_build.h"
|
||||
#include "sbc_handler.h"
|
||||
|
||||
void sbc_handle_write_replace_warning_request(sbc_pws_data_t *sbc_pws)
|
||||
{
|
||||
pkbuf_t *s1apbuf = NULL;
|
||||
hash_index_t *hi = NULL;
|
||||
mme_enb_t *enb = NULL;
|
||||
int i, j, flag;
|
||||
status_t rv;
|
||||
|
||||
/* Find enB with matched TAI */
|
||||
for (hi = mme_enb_first(); hi; hi = mme_enb_next(hi))
|
||||
{
|
||||
flag = 0;
|
||||
enb = mme_enb_this(hi);
|
||||
if (sbc_pws->no_of_tai > 0)
|
||||
{
|
||||
for (i = 0, flag = 0; i < enb->num_of_supported_ta_list; i++)
|
||||
{
|
||||
for (j = 0; j < sbc_pws->no_of_tai; j++)
|
||||
{
|
||||
if (!memcmp(&enb->supported_ta_list[i],
|
||||
&sbc_pws->tai[j], sizeof(tai_t)))
|
||||
flag = 1;
|
||||
|
||||
if (flag) break;
|
||||
}
|
||||
if (flag) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
flag = 1;
|
||||
|
||||
if (flag)
|
||||
{
|
||||
s1apbuf = NULL;
|
||||
|
||||
/* Buidl S1AP Write Replace Warning Request message */
|
||||
rv = s1ap_build_write_replace_warning_request(&s1apbuf, sbc_pws);
|
||||
d_assert(rv == CORE_OK && s1apbuf, return,
|
||||
"s1ap build error");
|
||||
|
||||
/* Send to enb */
|
||||
d_assert(s1ap_send_to_enb(
|
||||
enb, s1apbuf, S1AP_NON_UE_SIGNALLING) == CORE_OK,
|
||||
return, "s1ap send error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sbc_handle_stop_warning_request(sbc_pws_data_t *sbc_pws)
|
||||
{
|
||||
pkbuf_t *s1apbuf = NULL;
|
||||
hash_index_t *hi = NULL;
|
||||
mme_enb_t *enb = NULL;
|
||||
int i, j, flag;
|
||||
status_t rv;
|
||||
|
||||
/* Find enB with matched TAI */
|
||||
for (hi = mme_enb_first(); hi; hi = mme_enb_next(hi))
|
||||
{
|
||||
flag = 0;
|
||||
enb = mme_enb_this(hi);
|
||||
if (sbc_pws->no_of_tai > 0)
|
||||
{
|
||||
for (i = 0, flag = 0; i < enb->num_of_supported_ta_list; i++)
|
||||
{
|
||||
for (j = 0; j < sbc_pws->no_of_tai; j++)
|
||||
{
|
||||
if (!memcmp(&enb->supported_ta_list[i],
|
||||
&sbc_pws->tai[j], sizeof(tai_t)))
|
||||
flag = 1;
|
||||
|
||||
if (flag) break;
|
||||
}
|
||||
if (flag) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
flag = 1;
|
||||
|
||||
if (flag)
|
||||
{
|
||||
s1apbuf = NULL;
|
||||
|
||||
/* Buidl S1AP Kill request message */
|
||||
rv = s1ap_build_kill_request(&s1apbuf, sbc_pws);
|
||||
d_assert(rv == CORE_OK && s1apbuf, return,
|
||||
"s1ap build error");
|
||||
|
||||
/* Send to enb */
|
||||
d_assert(s1ap_send_to_enb(
|
||||
enb, s1apbuf, S1AP_NON_UE_SIGNALLING) == CORE_OK,
|
||||
return, "s1ap send error");
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/mme/sbc_handler.h
Normal file
19
src/mme/sbc_handler.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef __SBC_HANDLER_H__
|
||||
#define __SBC_HANDLER_H__
|
||||
|
||||
#include "sbc_message.h"
|
||||
|
||||
/* SBc-AP handles */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
CORE_DECLARE(void) sbc_handle_write_replace_warning_request(sbc_pws_data_t *sbc_pws);
|
||||
CORE_DECLARE(void) sbc_handle_stop_warning_request(sbc_pws_data_t *sbc_pws);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __SBC_HANDLER_H__ */
|
||||
34
src/mme/sbc_message.h
Normal file
34
src/mme/sbc_message.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef __SBC_MESSAGE_H__
|
||||
#define __SBC_MESSAGE_H__
|
||||
|
||||
#include "3gpp_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* SBc-AP messages:
|
||||
* After the CBC integration, the encoding/decoding of
|
||||
* SBc-AP messages will be fully supported.
|
||||
*/
|
||||
|
||||
/* SBc-AP interface data definitions */
|
||||
|
||||
/* SBc-AP WriteReplaceWarning data */
|
||||
typedef struct _sbc_pws_data_t {
|
||||
c_uint16_t message_id;
|
||||
c_uint16_t serial_number;
|
||||
c_uint32_t no_of_tai;
|
||||
tai_t tai[16]; /* TODO: max 65535 */
|
||||
c_uint32_t repetition_period;
|
||||
c_uint32_t number_of_broadcast;
|
||||
c_uint8_t data_coding_scheme;
|
||||
c_uint32_t message_length;
|
||||
c_uint8_t message_contents[1024]; /* TODO: max 9600 */
|
||||
} sbc_pws_data_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __SBC_MESSAGE_H__ */
|
||||
@@ -1082,7 +1082,7 @@ gtp_node_t *pgw_sgw_add_by_message(gtp_message_t *message)
|
||||
sgw = gtp_find_node(&pgw_self()->sgw_s5c_list, sgw_s5c_teid);
|
||||
if (!sgw)
|
||||
{
|
||||
sgw = gtp_add_node_with_teid(&pgw_self()->sgw_s5c_list, sgw_s5c_teid,
|
||||
sgw = gtp_add_node(&pgw_self()->sgw_s5c_list, sgw_s5c_teid,
|
||||
pgw_self()->gtpc_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
|
||||
@@ -86,7 +86,7 @@ void pgw_s5c_handle_create_session_request(
|
||||
sgw = gtp_find_node(&pgw_self()->sgw_s5u_list, sgw_s5u_teid);
|
||||
if (!sgw)
|
||||
{
|
||||
sgw = gtp_add_node_with_teid(&pgw_self()->sgw_s5u_list, sgw_s5u_teid,
|
||||
sgw = gtp_add_node(&pgw_self()->sgw_s5u_list, sgw_s5u_teid,
|
||||
pgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
@@ -190,7 +190,7 @@ void pgw_s5c_handle_create_bearer_response(
|
||||
sgw = gtp_find_node(&pgw_self()->sgw_s5u_list, sgw_s5u_teid);
|
||||
if (!sgw)
|
||||
{
|
||||
sgw = gtp_add_node_with_teid(&pgw_self()->sgw_s5u_list, sgw_s5u_teid,
|
||||
sgw = gtp_add_node(&pgw_self()->sgw_s5u_list, sgw_s5u_teid,
|
||||
pgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
|
||||
@@ -514,7 +514,7 @@ gtp_node_t *sgw_mme_add_by_message(gtp_message_t *message)
|
||||
mme = gtp_find_node(&sgw_self()->mme_s11_list, mme_s11_teid);
|
||||
if (!mme)
|
||||
{
|
||||
mme = gtp_add_node_with_teid(&sgw_self()->mme_s11_list, mme_s11_teid,
|
||||
mme = gtp_add_node(&sgw_self()->mme_s11_list, mme_s11_teid,
|
||||
sgw_self()->gtpc_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
|
||||
@@ -38,7 +38,7 @@ void sgw_s11_handle_create_session_request(
|
||||
|
||||
req = >p_message->create_session_request;
|
||||
|
||||
d_trace(3, "[SGW] Create Session Reqeust\n");
|
||||
d_trace(3, "[SGW] Create Session Request\n");
|
||||
if (req->bearer_contexts_to_be_created.presence == 0)
|
||||
{
|
||||
d_error("No Bearer");
|
||||
@@ -120,7 +120,7 @@ void sgw_s11_handle_create_session_request(
|
||||
pgw = gtp_find_node(&sgw_self()->pgw_s5c_list, pgw_s5c_teid);
|
||||
if (!pgw)
|
||||
{
|
||||
pgw = gtp_add_node_with_teid(&sgw_self()->pgw_s5c_list, pgw_s5c_teid,
|
||||
pgw = gtp_add_node(&sgw_self()->pgw_s5c_list, pgw_s5c_teid,
|
||||
sgw_self()->gtpc_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
@@ -227,7 +227,7 @@ CORE_DECLARE(void) sgw_s11_handle_modify_bearer_request(gtp_xact_t *s11_xact,
|
||||
enb = gtp_find_node(&sgw_self()->enb_s1u_list, enb_s1u_teid);
|
||||
if (!enb)
|
||||
{
|
||||
enb = gtp_add_node_with_teid(&sgw_self()->enb_s1u_list, enb_s1u_teid,
|
||||
enb = gtp_add_node(&sgw_self()->enb_s1u_list, enb_s1u_teid,
|
||||
sgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
@@ -460,7 +460,7 @@ void sgw_s11_handle_create_bearer_response(gtp_xact_t *s11_xact,
|
||||
enb = gtp_find_node(&sgw_self()->enb_s1u_list, enb_s1u_teid);
|
||||
if (!enb)
|
||||
{
|
||||
enb = gtp_add_node_with_teid(&sgw_self()->enb_s1u_list, enb_s1u_teid,
|
||||
enb = gtp_add_node(&sgw_self()->enb_s1u_list, enb_s1u_teid,
|
||||
sgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
@@ -830,8 +830,7 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
|
||||
enb = gtp_find_node(&sgw_self()->enb_s1u_list, req_teid);
|
||||
if (!enb)
|
||||
{
|
||||
enb = gtp_add_node_with_teid(
|
||||
&sgw_self()->enb_s1u_list, req_teid,
|
||||
enb = gtp_add_node(&sgw_self()->enb_s1u_list, req_teid,
|
||||
sgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
@@ -871,8 +870,7 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
|
||||
enb = gtp_find_node(&sgw_self()->enb_s1u_list, req_teid);
|
||||
if (!enb)
|
||||
{
|
||||
enb = gtp_add_node_with_teid(
|
||||
&sgw_self()->enb_s1u_list, req_teid,
|
||||
enb = gtp_add_node(&sgw_self()->enb_s1u_list, req_teid,
|
||||
sgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
|
||||
@@ -98,7 +98,7 @@ void sgw_s5c_handle_create_session_response(gtp_xact_t *s5c_xact,
|
||||
pgw = gtp_find_node(&sgw_self()->pgw_s5u_list, pgw_s5u_teid);
|
||||
if (!pgw)
|
||||
{
|
||||
pgw = gtp_add_node_with_teid(&sgw_self()->pgw_s5u_list, pgw_s5u_teid,
|
||||
pgw = gtp_add_node(&sgw_self()->pgw_s5u_list, pgw_s5u_teid,
|
||||
sgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
@@ -286,7 +286,7 @@ void sgw_s5c_handle_create_bearer_request(gtp_xact_t *s5c_xact,
|
||||
pgw = gtp_find_node(&sgw_self()->pgw_s5u_list, pgw_s5u_teid);
|
||||
if (!pgw)
|
||||
{
|
||||
pgw = gtp_add_node_with_teid(&sgw_self()->pgw_s5u_list, pgw_s5u_teid,
|
||||
pgw = gtp_add_node(&sgw_self()->pgw_s5u_list, pgw_s5u_teid,
|
||||
sgw_self()->gtpu_port,
|
||||
context_self()->parameter.no_ipv4,
|
||||
context_self()->parameter.no_ipv6,
|
||||
|
||||
@@ -203,7 +203,29 @@ sgw:
|
||||
addr: 127.0.0.2
|
||||
|
||||
#
|
||||
# <GTP-U Server>>
|
||||
# <SGW Selection Mode>
|
||||
#
|
||||
# o Round-Robin
|
||||
# (If `selection_mode` is omitted, the default mode is Round-Robin)
|
||||
#
|
||||
# selection_mode: rr
|
||||
# gtpc:
|
||||
# addr: 127.0.0.2
|
||||
# addr: 127.0.2.2
|
||||
# addr: 127.0.4.2
|
||||
#
|
||||
# o SGW selection by eNodeB TAC
|
||||
#
|
||||
# selection_mode: tac
|
||||
# gtpc:
|
||||
# - addr: 127.0.0.2
|
||||
# tac: 26000
|
||||
# - addr: 127.0.2.2
|
||||
# tac: [25000, 27000, 28000]
|
||||
#
|
||||
|
||||
#
|
||||
# <GTP-U Server>
|
||||
#
|
||||
# o GTP-U Server(all address avaiable)
|
||||
# gtpu:
|
||||
|
||||
@@ -56,7 +56,8 @@ services:
|
||||
- base
|
||||
environment:
|
||||
- DB_URI=mongodb://mongodb/nextepc
|
||||
- DISPLAY=docker.for.mac.localhost:0
|
||||
- DISPLAY=$DISPLAY
|
||||
# - DISPLAY=docker.for.mac.localhost:0
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
@@ -67,6 +68,8 @@ services:
|
||||
- home:/home/${USER}
|
||||
- ${HOME}:/mnt
|
||||
- /tmp/.X11-unix:/tmp/.X11-unix
|
||||
# - /etc/localtime:/etc/localtime:ro
|
||||
# - /usr/share/zoneinfo/Europe/Helsinki:/etc/localtime:ro
|
||||
hostname: nextepc-dev
|
||||
user: ${USER}
|
||||
entrypoint: /bin/bash -c "/bin/bash -c \"$${@}\""
|
||||
|
||||
@@ -155,7 +155,7 @@ static void gtp_message_test1(abts_case *tc, void *data)
|
||||
&bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN);
|
||||
|
||||
memset(&ue_timezone, 0, sizeof(ue_timezone));
|
||||
ue_timezone.gmtoff = 0x40;
|
||||
ue_timezone.timezone = 0x40;
|
||||
ue_timezone.daylight_saving_time =
|
||||
GTP_UE_TIME_ZONE_NO_ADJUSTMENT_FOR_DAYLIGHT_SAVING_TIME;
|
||||
req.ue_time_zone.presence = 1;
|
||||
|
||||
@@ -57,6 +57,7 @@ static void nas_message_test2(abts_case *tc, void *data)
|
||||
nas_attach_accept_t *attach_accept = &message.emm.attach_accept;
|
||||
tai0_list_t tai0_list;
|
||||
tai2_list_t tai2_list;
|
||||
plmn_id_t plmn_id;
|
||||
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
status_t rv;
|
||||
@@ -85,15 +86,16 @@ static void nas_message_test2(abts_case *tc, void *data)
|
||||
attach_accept->presencemask |= NAS_ATTACH_ACCEPT_GUTI_PRESENT;
|
||||
attach_accept->guti.length = 11;
|
||||
attach_accept->guti.guti.type = NAS_EPS_MOBILE_IDENTITY_GUTI;
|
||||
plmn_id_build(&attach_accept->guti.guti.plmn_id, 417, 99, 2);
|
||||
nas_from_plmn_id(&attach_accept->guti.guti.plmn_id,
|
||||
plmn_id_build(&plmn_id, 417, 99, 2));
|
||||
attach_accept->guti.guti.mme_gid = 9029;
|
||||
attach_accept->guti.guti.mme_code = 225;
|
||||
attach_accept->guti.guti.m_tmsi = 0x00000456;
|
||||
|
||||
attach_accept->presencemask |=
|
||||
NAS_ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT;
|
||||
plmn_id_build(
|
||||
&attach_accept->location_area_identification.plmn_id, 1, 2, 2);
|
||||
nas_from_plmn_id(&attach_accept->location_area_identification.plmn_id,
|
||||
plmn_id_build(&plmn_id, 1, 2, 2));
|
||||
attach_accept->location_area_identification.lac = 0xfffd;
|
||||
|
||||
attach_accept->presencemask |= NAS_ATTACH_ACCEPT_MS_IDENTITY_PRESENT;
|
||||
|
||||
@@ -165,6 +165,33 @@ static void s1ap_message_test6(abts_case *tc, void *data)
|
||||
pkbuf_free(s1apbuf);
|
||||
}
|
||||
|
||||
static void s1ap_message_test7(abts_case *tc, void *data)
|
||||
{
|
||||
/* InitialUE(Service Request) */
|
||||
char *payload =
|
||||
"000c402d000005000800020071001a00 0504c706b410004300060013f1890001"
|
||||
"006440080013f189400bb75000864001 40006440080013f189400bb750004340"
|
||||
"060013f18900014300060013f1890001 006440080013f189400db09000864001"
|
||||
"30000000000000000000000000000000 00000000000000000000000000000000";
|
||||
|
||||
s1ap_message_t message;
|
||||
pkbuf_t *pkbuf;
|
||||
int result;
|
||||
char hexbuf[MAX_SDU_LEN];
|
||||
|
||||
pkbuf = pkbuf_alloc(0, MAX_SDU_LEN);
|
||||
ABTS_PTR_NOTNULL(tc, pkbuf);
|
||||
pkbuf->len = 8192;
|
||||
memcpy(pkbuf->payload,
|
||||
CORE_HEX(payload, strlen(payload), hexbuf), 128);
|
||||
|
||||
result = s1ap_decode_pdu(&message, pkbuf);
|
||||
ABTS_INT_EQUAL(tc, 0, result);
|
||||
s1ap_free_pdu(&message);
|
||||
|
||||
pkbuf_free(pkbuf);
|
||||
}
|
||||
|
||||
abts_suite *test_s1ap_message(abts_suite *suite)
|
||||
{
|
||||
suite = ADD_SUITE(suite)
|
||||
@@ -175,6 +202,7 @@ abts_suite *test_s1ap_message(abts_suite *suite)
|
||||
abts_run_test(suite, s1ap_message_test4, NULL);
|
||||
abts_run_test(suite, s1ap_message_test5, NULL);
|
||||
abts_run_test(suite, s1ap_message_test6, NULL);
|
||||
abts_run_test(suite, s1ap_message_test7, NULL);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ static void s1setup_test1(abts_case *tc, void *data)
|
||||
for (i = 0; i < NUM_OF_TEST_DUPLICATED_ENB; i++)
|
||||
{
|
||||
rv = tests1ap_build_setup_req(
|
||||
&sendbuf, S1AP_ENB_ID_PR_macroENB_ID, 0x54f64);
|
||||
&sendbuf, S1AP_ENB_ID_PR_macroENB_ID, 0);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
|
||||
rv = tests1ap_enb_send(sock[i], sendbuf);
|
||||
@@ -75,7 +75,7 @@ static void s1setup_test2(abts_case *tc, void *data)
|
||||
for (i = 0; i < NUM_OF_TEST_ENB; i++)
|
||||
{
|
||||
rv = tests1ap_build_setup_req(
|
||||
&sendbuf, S1AP_ENB_ID_PR_macroENB_ID, 0x54f64+i);
|
||||
&sendbuf, S1AP_ENB_ID_PR_macroENB_ID, i);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
|
||||
rv = tests1ap_enb_send(sock[i], sendbuf);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nextepc",
|
||||
"version": "0.3.10",
|
||||
"version": "0.3.11",
|
||||
"description": "NextEPC",
|
||||
"main": "index.js",
|
||||
"repository": "https://github.com/acetcom/nextepc",
|
||||
|
||||
Reference in New Issue
Block a user