mirror of https://github.com/pvnis/srsRAN_4G.git
Adding Downlink data notification and paging functionality to the EPC.
This entails: * Adding S1AP paging messaging to the MME. * Adding the Downlink Data Notification, Donlink Data Notification Acknoledgment, and Downlink Data Notification Failure Messages. * Adding the logic at the GTP-U to detect that Downlink Data notification needs to be sent. * Proper handling of the new GTP-C messages at the MME GTPC and SPGW GTPC classes * Add queuing mechanisms at the GTP-U while waiting for paging response. Queue is flushed when paging fails (timeout or other). * Make sure eNB's SCTP information is properly stored. * Make sure UE's GUTI information is properly stored.master
parent
1db959c661
commit
ca603810ce
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2017 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE 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.
|
||||||
|
*
|
||||||
|
* srsLTE 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef SRSEPC_S1AP_PAGING_H
|
||||||
|
#define SRSEPC_S1AP_PAGING_H
|
||||||
|
|
||||||
|
#include "s1ap_common.h"
|
||||||
|
#include "srslte/asn1/liblte_s1ap.h"
|
||||||
|
#include "srslte/common/buffer_pool.h"
|
||||||
|
#include "srslte/common/common.h"
|
||||||
|
#include "srslte/common/log_filter.h"
|
||||||
|
|
||||||
|
namespace srsepc {
|
||||||
|
|
||||||
|
class s1ap;
|
||||||
|
class mme;
|
||||||
|
|
||||||
|
class s1ap_paging
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static s1ap_paging* m_instance;
|
||||||
|
static s1ap_paging* get_instance(void);
|
||||||
|
static void cleanup(void);
|
||||||
|
void init(void);
|
||||||
|
|
||||||
|
// Packing/unpacking helper functions
|
||||||
|
bool send_paging(uint64_t imsi, uint16_t erab_to_setup);
|
||||||
|
|
||||||
|
private:
|
||||||
|
s1ap_paging();
|
||||||
|
virtual ~s1ap_paging();
|
||||||
|
|
||||||
|
mme* m_mme;
|
||||||
|
s1ap* m_s1ap;
|
||||||
|
srslte::log_filter* m_s1ap_log;
|
||||||
|
|
||||||
|
s1ap_args_t m_s1ap_args;
|
||||||
|
srslte::byte_buffer_pool* m_pool;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace srsepc
|
||||||
|
|
||||||
|
#endif // SRSEPC_S1AP_PAGING_H
|
@ -0,0 +1,164 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2017 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of srsLTE.
|
||||||
|
*
|
||||||
|
* srsLTE 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.
|
||||||
|
*
|
||||||
|
* srsLTE 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "srsepc/hdr/mme/s1ap_paging.h"
|
||||||
|
#include "srsepc/hdr/mme/mme.h"
|
||||||
|
#include "srsepc/hdr/mme/s1ap.h"
|
||||||
|
#include "srslte/common/bcd_helpers.h"
|
||||||
|
#include "srslte/common/int_helpers.h"
|
||||||
|
|
||||||
|
namespace srsepc {
|
||||||
|
|
||||||
|
s1ap_paging* s1ap_paging::m_instance = NULL;
|
||||||
|
pthread_mutex_t s1ap_paging_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
s1ap_paging::s1ap_paging()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s1ap_paging::~s1ap_paging()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s1ap_paging* s1ap_paging::get_instance(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&s1ap_paging_instance_mutex);
|
||||||
|
if (NULL == m_instance) {
|
||||||
|
m_instance = new s1ap_paging();
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&s1ap_paging_instance_mutex);
|
||||||
|
return (m_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s1ap_paging::cleanup(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&s1ap_paging_instance_mutex);
|
||||||
|
if (NULL != m_instance) {
|
||||||
|
delete m_instance;
|
||||||
|
m_instance = NULL;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&s1ap_paging_instance_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void s1ap_paging::init(void)
|
||||||
|
{
|
||||||
|
m_s1ap = s1ap::get_instance();
|
||||||
|
m_mme = mme::get_instance();
|
||||||
|
m_s1ap_log = m_s1ap->m_s1ap_log;
|
||||||
|
m_s1ap_args = m_s1ap->m_s1ap_args;
|
||||||
|
m_pool = srslte::byte_buffer_pool::get_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool s1ap_paging::send_paging(uint64_t imsi, uint16_t erab_to_setup)
|
||||||
|
{
|
||||||
|
m_s1ap_log->info("Preparing to Page UE -- IMSI %lu\n", imsi);
|
||||||
|
|
||||||
|
// Prepare reply PDU
|
||||||
|
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
|
||||||
|
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
|
||||||
|
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
|
||||||
|
|
||||||
|
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* init = &pdu.choice.initiatingMessage;
|
||||||
|
init->procedureCode = LIBLTE_S1AP_PROC_ID_PAGING;
|
||||||
|
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PAGING;
|
||||||
|
LIBLTE_S1AP_MESSAGE_PAGING_STRUCT* paging = &init->choice.Paging;
|
||||||
|
|
||||||
|
// Getting UE NAS Context
|
||||||
|
nas* nas_ctx = m_s1ap->find_nas_ctx_from_imsi(imsi);
|
||||||
|
if (nas_ctx == NULL) {
|
||||||
|
m_s1ap_log->error("Could not find UE to page NAS context\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UE Identity Index
|
||||||
|
uint16_t ue_index = imsi % 1024; // LIBLTE_S1AP_UEIDENTITYINDEXVALUE_BIT_STRING_LEN == 10
|
||||||
|
uint8_t* tmp_ptr = paging->UEIdentityIndexValue.buffer;
|
||||||
|
liblte_value_2_bits(ue_index, &tmp_ptr, 10);
|
||||||
|
|
||||||
|
// UE Paging Id
|
||||||
|
paging->UEPagingID.choice_type = LIBLTE_S1AP_UEPAGINGID_CHOICE_S_TMSI;
|
||||||
|
paging->UEPagingID.choice.s_TMSI.ext = false;
|
||||||
|
paging->UEPagingID.choice.s_TMSI.mMEC.buffer[0] = m_s1ap->m_s1ap_args.mme_code;
|
||||||
|
uint32_t m_tmsi = nas_ctx->m_sec_ctx.guti.m_tmsi;
|
||||||
|
srslte::uint32_to_uint8(m_tmsi, paging->UEPagingID.choice.s_TMSI.m_TMSI.buffer);
|
||||||
|
paging->UEPagingID.choice.s_TMSI.iE_Extensions_present = false;
|
||||||
|
|
||||||
|
// Paging DRX
|
||||||
|
paging->pagingDRX_present = false;
|
||||||
|
|
||||||
|
// CMDomain
|
||||||
|
paging->CNDomain = LIBLTE_S1AP_CNDOMAIN_PS;
|
||||||
|
|
||||||
|
// TAI List
|
||||||
|
paging->TAIList.len = 1;
|
||||||
|
paging->TAIList.buffer[0].ext = false;
|
||||||
|
paging->TAIList.buffer[0].tAI.ext = false;
|
||||||
|
uint32_t plmn = htonl(m_s1ap->get_plmn()); // LIBLTE_S1AP_TBCD_STRING_OCTET_STRING_LEN == 3
|
||||||
|
paging->TAIList.buffer[0].tAI.pLMNidentity.buffer[0] = ((uint8_t*)&plmn)[1];
|
||||||
|
paging->TAIList.buffer[0].tAI.pLMNidentity.buffer[1] = ((uint8_t*)&plmn)[2];
|
||||||
|
paging->TAIList.buffer[0].tAI.pLMNidentity.buffer[2] = ((uint8_t*)&plmn)[3];
|
||||||
|
uint16_t tac = htons(m_s1ap->m_s1ap_args.tac); // LIBLTE_S1AP_TAC_OCTET_STRING_LEN == 2
|
||||||
|
memcpy(paging->TAIList.buffer[0].tAI.tAC.buffer, &tac, sizeof(uint16_t));
|
||||||
|
paging->TAIList.buffer[0].tAI.iE_Extensions_present = false;
|
||||||
|
paging->TAIList.buffer[0].iE_Extensions_present = false;
|
||||||
|
|
||||||
|
// CSG Id List
|
||||||
|
paging->CSG_IdList_present = false;
|
||||||
|
|
||||||
|
// Paging Priority
|
||||||
|
paging->PagingPriority_present = false;
|
||||||
|
|
||||||
|
// Start T3413
|
||||||
|
if (!nas_ctx->start_timer(T_3413)) {
|
||||||
|
m_s1ap_log->error("Could not start T3413 -- Aborting paging\n");
|
||||||
|
// TODO Send data notification failure to SPGW
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Send Paging to eNBs
|
||||||
|
m_s1ap_log->info("Paging UE -- M-TMSI :0x%x\n", m_tmsi);
|
||||||
|
srslte::byte_buffer_t* reply_buffer = m_pool->allocate();
|
||||||
|
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer);
|
||||||
|
if (err != LIBLTE_SUCCESS) {
|
||||||
|
m_s1ap_log->error("Could not pack Paging Message\n");
|
||||||
|
m_pool->deallocate(reply_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::map<uint16_t, enb_ctx_t*>::iterator it = m_s1ap->m_active_enbs.begin(); it != m_s1ap->m_active_enbs.end();
|
||||||
|
it++) {
|
||||||
|
enb_ctx_t* enb_ctx = it->second;
|
||||||
|
if (!m_s1ap->s1ap_tx_pdu(reply_buffer, &enb_ctx->sri)) {
|
||||||
|
m_s1ap_log->error("Error paging to eNB. eNB Id: 0x%x.\n", enb_ctx->enb_id);
|
||||||
|
m_pool->deallocate(reply_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace srsepc
|
Loading…
Reference in New Issue