From efcd582b09993e8345184cceda67022ec0fac7ab Mon Sep 17 00:00:00 2001
From: Lionel Gauthier <lionel.gauthier@eurecom.fr>
Date: Tue, 9 Dec 2014 19:43:47 +0000
Subject: [PATCH] UE_CONTEXT_RELEASE_COMPLETE

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@6223 818b1a75-f10b-46b9-bf7c-635c3b92a50f
---
 openair-cn/S1AP/s1ap_eNB.c                |  4 ++
 openair-cn/S1AP/s1ap_eNB_encoder.c        | 76 ++++++++++++++++++-----
 openair-cn/S1AP/s1ap_eNB_itti_messaging.c | 13 ++++
 openair-cn/S1AP/s1ap_eNB_itti_messaging.h |  4 ++
 openair-cn/S1AP/s1ap_eNB_nas_procedures.c | 72 +++++++++++++++++++++
 openair-cn/S1AP/s1ap_eNB_nas_procedures.h |  4 ++
 openair-cn/S1AP/s1ap_eNB_ue_context.h     |  3 +
 7 files changed, 161 insertions(+), 15 deletions(-)

diff --git a/openair-cn/S1AP/s1ap_eNB.c b/openair-cn/S1AP/s1ap_eNB.c
index e0d0629ff6..18137475be 100644
--- a/openair-cn/S1AP/s1ap_eNB.c
+++ b/openair-cn/S1AP/s1ap_eNB.c
@@ -296,6 +296,10 @@ void *s1ap_eNB_task(void *arg)
                 s1ap_eNB_nas_non_delivery_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                               &S1AP_NAS_NON_DELIVERY_IND(received_msg));
             } break;
+            case S1AP_UE_CONTEXT_RELEASE_COMPLETE: {
+                s1ap_ue_context_release_complete(ITTI_MESSAGE_GET_INSTANCE(received_msg),
+                                              &S1AP_UE_CONTEXT_RELEASE_COMPLETE(received_msg));
+            } break;
             default:
                 S1AP_ERROR("Received unhandled message: %d:%s\n",
                            ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
diff --git a/openair-cn/S1AP/s1ap_eNB_encoder.c b/openair-cn/S1AP/s1ap_eNB_encoder.c
index c8d4cc9618..821f791747 100644
--- a/openair-cn/S1AP/s1ap_eNB_encoder.c
+++ b/openair-cn/S1AP/s1ap_eNB_encoder.c
@@ -89,6 +89,13 @@ int s1ap_eNB_encode_nas_non_delivery(
     uint8_t                            **buffer,
     uint32_t                            *length);
 
+static inline
+int s1ap_eNB_encode_ue_context_release_complete(
+    S1ap_UEContextReleaseCompleteIEs_t *s1ap_UEContextReleaseCompleteIEs,
+    uint8_t                           **buffer,
+    uint32_t                           *length);
+
+
 int s1ap_eNB_encode_pdu(s1ap_message *message, uint8_t **buffer, uint32_t *len)
 {
     DevAssert(message != NULL);
@@ -198,14 +205,34 @@ int s1ap_eNB_encode_successfull_outcome(s1ap_message *s1ap_message_p,
     message_string = calloc(10000, sizeof(char));
 
     s1ap_string_total_size = 0;
+    message_string_size = strlen(message_string);
+
 
     switch(s1ap_message_p->procedureCode) {
-        case S1ap_ProcedureCode_id_InitialContextSetup:
-            ret = s1ap_eNB_encode_initial_context_setup_response(
-                &s1ap_message_p->msg.s1ap_InitialContextSetupResponseIEs, buffer, len);
-            s1ap_xer_print_s1ap_initialcontextsetupresponse(s1ap_xer__print2sp, message_string, s1ap_message_p);
-            message_id = S1AP_INITIAL_CONTEXT_SETUP_LOG;
-            break;
+    case S1ap_ProcedureCode_id_InitialContextSetup:
+        ret = s1ap_eNB_encode_initial_context_setup_response(
+            &s1ap_message_p->msg.s1ap_InitialContextSetupResponseIEs, buffer, len);
+
+        s1ap_xer_print_s1ap_initialcontextsetupresponse(s1ap_xer__print2sp, message_string, s1ap_message_p);
+        message_id = S1AP_INITIAL_CONTEXT_SETUP_LOG;
+        message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, message_string_size + sizeof (IttiMsgText));
+        message_p->ittiMsg.s1ap_initial_context_setup_log.size = message_string_size;
+        memcpy(&message_p->ittiMsg.s1ap_initial_context_setup_log.text, message_string, message_string_size);
+        itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p);
+        free(message_string);
+        break;
+
+    case S1ap_ProcedureCode_id_UEContextRelease:
+        ret = s1ap_eNB_encode_ue_context_release_complete(
+            &s1ap_message_p->msg.s1ap_UEContextReleaseCompleteIEs, buffer, len);
+        s1ap_xer_print_s1ap_uecontextreleasecomplete(s1ap_xer__print2sp, message_string, s1ap_message_p);
+        message_id = S1AP_UE_CONTEXT_RELEASE_COMPLETE_LOG;
+        message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, message_string_size + sizeof (IttiMsgText));
+        message_p->ittiMsg.s1ap_ue_context_release_complete_log.size = message_string_size;
+        memcpy(&message_p->ittiMsg.s1ap_ue_context_release_complete_log.text, message_string, message_string_size);
+        itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p);
+        free(message_string);
+        break;
 
         default:
             S1AP_DEBUG("Unknown procedure ID (%d) for successfull outcome message\n",
@@ -214,15 +241,6 @@ int s1ap_eNB_encode_successfull_outcome(s1ap_message *s1ap_message_p,
             break;
     }
 
-    message_string_size = strlen(message_string);
-
-    message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, message_string_size + sizeof (IttiMsgText));
-    message_p->ittiMsg.s1ap_initial_context_setup_log.size = message_string_size;
-    memcpy(&message_p->ittiMsg.s1ap_initial_context_setup_log.text, message_string, message_string_size);
-
-    itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p);
-
-    free(message_string);
 
     return ret;
 }
@@ -445,3 +463,31 @@ int s1ap_eNB_encode_initial_context_setup_response(
             &asn_DEF_S1ap_InitialContextSetupResponse,
             initial_context_setup_response_p);
 }
+
+static inline
+int s1ap_eNB_encode_ue_context_release_complete(
+		S1ap_UEContextReleaseCompleteIEs_t *s1ap_UEContextReleaseCompleteIEs,
+    uint8_t                              **buffer,
+    uint32_t                              *length)
+{
+	S1ap_UEContextReleaseComplete_t  ue_context_release_complete;
+	S1ap_UEContextReleaseComplete_t *ue_context_release_complete_p =
+        &ue_context_release_complete;
+
+    memset((void *)ue_context_release_complete_p, 0,
+           sizeof(ue_context_release_complete));
+
+    if (s1ap_encode_s1ap_uecontextreleasecompleteies(
+    		ue_context_release_complete_p, s1ap_UEContextReleaseCompleteIEs) < 0)
+    {
+        return -1;
+    }
+
+    return s1ap_generate_successfull_outcome(buffer,
+            length,
+            S1ap_ProcedureCode_id_UEContextRelease,
+            S1ap_Criticality_reject,
+            &asn_DEF_S1ap_UEContextReleaseComplete,
+            ue_context_release_complete_p);
+}
+
diff --git a/openair-cn/S1AP/s1ap_eNB_itti_messaging.c b/openair-cn/S1AP/s1ap_eNB_itti_messaging.c
index 8cb4e98f54..2eb9011e94 100644
--- a/openair-cn/S1AP/s1ap_eNB_itti_messaging.c
+++ b/openair-cn/S1AP/s1ap_eNB_itti_messaging.c
@@ -40,3 +40,16 @@ void s1ap_eNB_itti_send_nas_downlink_ind(instance_t instance,
 
     itti_send_msg_to_task(TASK_RRC_ENB, instance, message_p);
 }
+
+void s1ap_eNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id)
+{
+    MessageDef               *message_p = NULL;
+    sctp_close_association_t *sctp_close_association_p = NULL;
+
+    message_p = itti_alloc_new_message(TASK_S1AP, SCTP_CLOSE_ASSOCIATION);
+    sctp_close_association_p = &message_p->ittiMsg.sctp_close_association;
+    sctp_close_association_p->assoc_id      = assoc_id;
+
+    itti_send_msg_to_task(TASK_SCTP, instance, message_p);
+}
+
diff --git a/openair-cn/S1AP/s1ap_eNB_itti_messaging.h b/openair-cn/S1AP/s1ap_eNB_itti_messaging.h
index 2d9ac3ce0e..8a16d7aad2 100644
--- a/openair-cn/S1AP/s1ap_eNB_itti_messaging.h
+++ b/openair-cn/S1AP/s1ap_eNB_itti_messaging.h
@@ -38,4 +38,8 @@ void s1ap_eNB_itti_send_nas_downlink_ind(instance_t instance,
                                          uint8_t *nas_pdu,
                                          uint32_t nas_pdu_length);
 
+void s1ap_eNB_itti_send_sctp_close_association(instance_t instance,
+                                              int32_t assoc_id);
+
+
 #endif /* S1AP_ENB_ITTI_MESSAGING_H_ */
diff --git a/openair-cn/S1AP/s1ap_eNB_nas_procedures.c b/openair-cn/S1AP/s1ap_eNB_nas_procedures.c
index 608addc19a..49a9bf0109 100644
--- a/openair-cn/S1AP/s1ap_eNB_nas_procedures.c
+++ b/openair-cn/S1AP/s1ap_eNB_nas_procedures.c
@@ -572,3 +572,75 @@ int s1ap_eNB_ue_capabilities(instance_t instance,
 
     return ret;
 }
+
+int s1ap_ue_context_release_complete(instance_t instance,
+		s1ap_ue_release_complete_t *ue_release_complete_p)
+{
+    s1ap_eNB_instance_t          *s1ap_eNB_instance_p = NULL;
+    struct s1ap_eNB_ue_context_s *ue_context_p        = NULL;
+
+    S1ap_UEContextReleaseCompleteIEs_t *ue_ctxt_release_complete_ies_p = NULL;
+
+    s1ap_message  message;
+
+    uint8_t  *buffer;
+    uint32_t length;
+    int      ret = -1;
+
+    /* Retrieve the S1AP eNB instance associated with Mod_id */
+    s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance);
+
+    DevAssert(ue_release_complete_p != NULL);
+    DevAssert(s1ap_eNB_instance_p != NULL);
+
+    if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p,
+    		ue_release_complete_p->eNB_ue_s1ap_id)) == NULL)
+    {
+        /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
+        S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
+        		ue_release_complete_p->eNB_ue_s1ap_id);
+        return -1;
+    }
+
+    /* Prepare the S1AP message to encode */
+    memset(&message, 0, sizeof(s1ap_message));
+
+    message.direction     = S1AP_PDU_PR_successfulOutcome;
+    message.procedureCode = S1ap_ProcedureCode_id_UEContextRelease;
+    //message.criticality   = S1ap_Criticality_reject;
+    message.direction     = S1AP_PDU_PR_successfulOutcome;
+
+    ue_ctxt_release_complete_ies_p = &message.msg.s1ap_UEContextReleaseCompleteIEs;
+
+    ue_ctxt_release_complete_ies_p->eNB_UE_S1AP_ID = ue_release_complete_p->eNB_ue_s1ap_id;
+    ue_ctxt_release_complete_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
+    //ue_ctxt_release_complete_ies_p->criticalityDiagnostics
+    //ue_ctxt_release_complete_ies_p->presenceMask
+
+    if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
+        /* Encode procedure has failed... */
+        S1AP_ERROR("Failed to encode UE context release complete\n");
+        return -1;
+    }
+
+    /* UE associated signalling -> use the allocated stream */
+    s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
+                                     ue_context_p->mme_ref->assoc_id, buffer,
+                                     length, ue_context_p->stream);
+
+
+    s1ap_eNB_itti_send_sctp_close_association(s1ap_eNB_instance_p->instance,
+                                     ue_context_p->mme_ref->assoc_id);
+
+
+
+    // release UE context
+    struct s1ap_eNB_ue_context_s *ue_context2_p = NULL;
+    if ((ue_context2_p = RB_REMOVE(s1ap_ue_map, &s1ap_eNB_instance_p->s1ap_ue_head, ue_context_p))
+            == NULL)
+    {
+        s1ap_eNB_free_ue_context(ue_context2_p);
+    }
+    return ret;
+}
+
diff --git a/openair-cn/S1AP/s1ap_eNB_nas_procedures.h b/openair-cn/S1AP/s1ap_eNB_nas_procedures.h
index 2e68cf2e12..04d31b0f2a 100644
--- a/openair-cn/S1AP/s1ap_eNB_nas_procedures.h
+++ b/openair-cn/S1AP/s1ap_eNB_nas_procedures.h
@@ -49,4 +49,8 @@ int s1ap_eNB_initial_ctxt_resp(
 int s1ap_eNB_ue_capabilities(instance_t instance,
                              s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p);
 
+int s1ap_ue_context_release_complete(instance_t instance,
+                             s1ap_ue_release_complete_t *ue_release_complete_p);
+
+
 #endif /* S1AP_ENB_NAS_PROCEDURES_H_ */
diff --git a/openair-cn/S1AP/s1ap_eNB_ue_context.h b/openair-cn/S1AP/s1ap_eNB_ue_context.h
index 51dcb4d897..8e4906d05e 100644
--- a/openair-cn/S1AP/s1ap_eNB_ue_context.h
+++ b/openair-cn/S1AP/s1ap_eNB_ue_context.h
@@ -91,4 +91,7 @@ struct s1ap_eNB_ue_context_s *s1ap_eNB_get_ue_context(
     s1ap_eNB_instance_t *instance_p,
     uint32_t eNB_ue_s1ap_id);
 
+void s1ap_eNB_free_ue_context(struct s1ap_eNB_ue_context_s *ue_context_p);
+
+
 #endif /* S1AP_ENB_UE_CONTEXT_H_ */
-- 
GitLab