forked from acouzens/open5gs
181 lines
6.3 KiB
C
181 lines
6.3 KiB
C
/*
|
|
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
|
*
|
|
* This file is part of Open5GS.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "s11-build.h"
|
|
|
|
ogs_pkbuf_t *sgwc_s11_build_create_session_response(
|
|
uint8_t type, sgwc_sess_t *sess)
|
|
{
|
|
int rv, i;
|
|
sgwc_bearer_t *bearer = NULL;
|
|
sgwc_tunnel_t *ul_tunnel = NULL;
|
|
sgwc_ue_t *sgwc_ue = NULL;
|
|
|
|
ogs_gtp2_message_t gtp_message;
|
|
ogs_gtp2_create_session_response_t *rsp = NULL;
|
|
|
|
ogs_gtp2_cause_t cause;
|
|
|
|
ogs_gtp2_f_teid_t sgw_s11_teid;
|
|
int len;
|
|
|
|
ogs_gtp2_cause_t bearer_cause[OGS_BEARER_PER_UE];
|
|
ogs_gtp2_f_teid_t sgw_s1u_teid[OGS_BEARER_PER_UE];
|
|
int sgw_s1u_len[OGS_BEARER_PER_UE];
|
|
ogs_gtp2_f_teid_t pgw_s5u_teid[OGS_BEARER_PER_UE];
|
|
int pgw_s5u_len[OGS_BEARER_PER_UE];
|
|
|
|
ogs_debug("[SGWC] Create Session Response");
|
|
|
|
ogs_assert(sess);
|
|
sgwc_ue = sess->sgwc_ue;
|
|
ogs_assert(sgwc_ue);
|
|
|
|
ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]",
|
|
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
|
|
|
|
rsp = >p_message.create_session_response;
|
|
memset(>p_message, 0, sizeof(ogs_gtp2_message_t));
|
|
|
|
/* Set Cause */
|
|
memset(&cause, 0, sizeof(cause));
|
|
rsp->cause.presence = 1;
|
|
rsp->cause.len = sizeof(cause);
|
|
rsp->cause.data = &cause;
|
|
|
|
cause.value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED;
|
|
|
|
/* Send Control Plane(UL) : SGW-S11 */
|
|
memset(&sgw_s11_teid, 0, sizeof(ogs_gtp2_f_teid_t));
|
|
sgw_s11_teid.interface_type = OGS_GTP2_F_TEID_S11_S4_SGW_GTP_C;
|
|
sgw_s11_teid.teid = htobe32(sgwc_ue->sgw_s11_teid);
|
|
rv = ogs_gtp2_sockaddr_to_f_teid(
|
|
ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6,
|
|
&sgw_s11_teid, &len);
|
|
ogs_assert(rv == OGS_OK);
|
|
rsp->sender_f_teid_for_control_plane.presence = 1;
|
|
rsp->sender_f_teid_for_control_plane.data = &sgw_s11_teid;
|
|
rsp->sender_f_teid_for_control_plane.len = len;
|
|
|
|
i = 0;
|
|
ogs_list_for_each(&sess->bearer_list, bearer) {
|
|
ogs_assert(i < OGS_BEARER_PER_UE);
|
|
|
|
/* Bearer EBI */
|
|
rsp->bearer_contexts_created[i].presence = 1;
|
|
rsp->bearer_contexts_created[i].eps_bearer_id.presence = 1;
|
|
rsp->bearer_contexts_created[i].eps_bearer_id.u8 = bearer->ebi;
|
|
|
|
/* Bearer Cause */
|
|
memset(&bearer_cause[i], 0, sizeof(bearer_cause[i]));
|
|
rsp->bearer_contexts_created[i].cause.presence = 1;
|
|
rsp->bearer_contexts_created[i].cause.len = sizeof(bearer_cause[i]);
|
|
rsp->bearer_contexts_created[i].cause.data = &bearer_cause[i];
|
|
bearer_cause[i].value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED;
|
|
|
|
/* Data Plane(UL) */
|
|
ul_tunnel = sgwc_ul_tunnel_in_bearer(bearer);
|
|
ogs_assert(ul_tunnel);
|
|
|
|
ogs_debug(" SGW_S1U_TEID[0x%x] PGW_S5U_TEID[0x%x]",
|
|
ul_tunnel->local_teid, ul_tunnel->remote_teid);
|
|
|
|
/* Data Plane(UL) : SGW-S1U */
|
|
memset(&sgw_s1u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t));
|
|
sgw_s1u_teid[i].interface_type = ul_tunnel->interface_type;
|
|
sgw_s1u_teid[i].teid = htobe32(ul_tunnel->local_teid);
|
|
ogs_assert(ul_tunnel->local_addr || ul_tunnel->local_addr6);
|
|
rv = ogs_gtp2_sockaddr_to_f_teid(
|
|
ul_tunnel->local_addr, ul_tunnel->local_addr6,
|
|
&sgw_s1u_teid[i], &sgw_s1u_len[i]);
|
|
ogs_assert(rv == OGS_OK);
|
|
rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.presence = 1;
|
|
rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.data =
|
|
&sgw_s1u_teid[i];
|
|
rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.len =
|
|
sgw_s1u_len[i];
|
|
|
|
/* Data Plane(UL) : PGW-S5U */
|
|
memset(&pgw_s5u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t));
|
|
pgw_s5u_teid[i].interface_type = OGS_GTP2_F_TEID_S5_S8_PGW_GTP_U;
|
|
pgw_s5u_teid[i].teid = htobe32(ul_tunnel->remote_teid);
|
|
rv = ogs_gtp2_ip_to_f_teid(&ul_tunnel->remote_ip,
|
|
&pgw_s5u_teid[i], &pgw_s5u_len[i]);
|
|
ogs_assert(rv == OGS_OK);
|
|
rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.presence = 1;
|
|
rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.data =
|
|
&pgw_s5u_teid[i];
|
|
rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.len =
|
|
pgw_s5u_len[i];
|
|
|
|
i++;
|
|
}
|
|
|
|
gtp_message.h.type = type;
|
|
return ogs_gtp2_build_msg(>p_message);
|
|
}
|
|
|
|
ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification(
|
|
uint8_t cause_value, sgwc_bearer_t *bearer)
|
|
{
|
|
ogs_gtp2_message_t message;
|
|
ogs_gtp2_downlink_data_notification_t *noti = NULL;
|
|
ogs_gtp2_cause_t cause;
|
|
ogs_gtp2_arp_t arp;
|
|
sgwc_sess_t *sess = NULL;
|
|
|
|
ogs_assert(bearer);
|
|
sess = bearer->sess;
|
|
ogs_assert(sess);
|
|
|
|
/* Build downlink notification message */
|
|
noti = &message.downlink_data_notification;
|
|
memset(&message, 0, sizeof(ogs_gtp2_message_t));
|
|
|
|
/*
|
|
* TS29.274 8.4 Cause Value
|
|
*
|
|
* 0 : Reserved. Shall not be sent and
|
|
* if received the Cause shall be treated as an invalid IE
|
|
*/
|
|
if (cause_value != OGS_GTP2_CAUSE_UNDEFINED_VALUE) {
|
|
memset(&cause, 0, sizeof(cause));
|
|
cause.value = cause_value;
|
|
noti->cause.presence = 1;
|
|
noti->cause.len = sizeof(cause);
|
|
noti->cause.data = &cause;
|
|
}
|
|
|
|
noti->eps_bearer_id.presence = 1;
|
|
noti->eps_bearer_id.u8 = bearer->ebi;
|
|
|
|
memset(&arp, 0, sizeof(arp));
|
|
arp.pre_emption_vulnerability =
|
|
sess->session.qos.arp.pre_emption_vulnerability;
|
|
arp.priority_level = sess->session.qos.arp.priority_level;
|
|
arp.pre_emption_capability = sess->session.qos.arp.pre_emption_capability;
|
|
|
|
noti->allocation_retention_priority.presence = 1;
|
|
noti->allocation_retention_priority.data = &arp;
|
|
noti->allocation_retention_priority.len = sizeof(arp);
|
|
|
|
message.h.type = OGS_GTP2_DOWNLINK_DATA_NOTIFICATION_TYPE;
|
|
return ogs_gtp2_build_msg(&message);
|
|
}
|