open5gs/src/sgwc/s11-build.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 = &gtp_message.create_session_response;
memset(&gtp_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(&gtp_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);
}