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