/* * Copyright (C) 2019 by Sukchan Lee * * 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 . */ #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); }