mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
8.8 KiB
C++
299 lines
8.8 KiB
C++
/*
|
|
* Copyright 2013-2019 Software Radio Systems Limited
|
|
*
|
|
* 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/.
|
|
*
|
|
*/
|
|
|
|
#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__)
|
|
#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__)
|
|
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
|
|
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
|
|
|
|
#include "srsue/hdr/stack/mac/demux.h"
|
|
#include "srslte/interfaces/ue_interfaces.h"
|
|
#include "srsue/hdr/stack/mac/mac.h"
|
|
|
|
namespace srsue {
|
|
|
|
demux::demux() :
|
|
mac_msg(20),
|
|
mch_mac_msg(20),
|
|
pending_mac_msg(20),
|
|
rlc(NULL),
|
|
is_uecrid_successful(false),
|
|
phy_h(nullptr),
|
|
log_h(nullptr),
|
|
time_alignment_timer(nullptr),
|
|
mac(nullptr)
|
|
{
|
|
}
|
|
|
|
void demux::init(phy_interface_mac_common* phy_h,
|
|
rlc_interface_mac* rlc,
|
|
mac_interface_demux* mac,
|
|
srslte::log* log_h,
|
|
srslte::timers::timer* time_alignment_timer)
|
|
{
|
|
this->phy_h = phy_h;
|
|
this->log_h = log_h;
|
|
this->rlc = rlc;
|
|
this->mac = mac;
|
|
this->time_alignment_timer = time_alignment_timer;
|
|
pdus.init(this, log_h);
|
|
bzero(&mch_lcids, SRSLTE_N_MCH_LCIDS);
|
|
}
|
|
|
|
bool demux::get_uecrid_successful() {
|
|
return is_uecrid_successful;
|
|
}
|
|
|
|
void demux::deallocate(uint8_t* payload_buffer_ptr)
|
|
{
|
|
if (payload_buffer_ptr != bcch_buffer) {
|
|
pdus.deallocate(payload_buffer_ptr);
|
|
}
|
|
}
|
|
uint8_t* demux::request_buffer_bcch(uint32_t len)
|
|
{
|
|
if (len < MAX_BCCH_PDU_LEN) {
|
|
return bcch_buffer;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
uint8_t* demux::request_buffer(uint32_t len)
|
|
{
|
|
return pdus.request(len);
|
|
}
|
|
|
|
/* Demultiplexing of MAC PDU associated with a Temporal C-RNTI. The PDU will
|
|
* remain in buffer until demultiplex_pending_pdu() is called.
|
|
* This features is provided to enable the Random Access Procedure to decide
|
|
* wether the PDU shall pass to upper layers or not, which depends on the
|
|
* Contention Resolution result.
|
|
*
|
|
* Warning: this function does some processing here assuming ACK deadline is not an
|
|
* issue here because Temp C-RNTI messages have small payloads
|
|
*/
|
|
void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes)
|
|
{
|
|
if (nof_bytes > 0) {
|
|
// Unpack DLSCH MAC PDU
|
|
pending_mac_msg.init_rx(nof_bytes);
|
|
pending_mac_msg.parse_packet(buff);
|
|
|
|
// Look for Contention Resolution UE ID
|
|
is_uecrid_successful = false;
|
|
while(pending_mac_msg.next() && !is_uecrid_successful) {
|
|
if (pending_mac_msg.get()->ce_type() == srslte::sch_subh::CON_RES_ID) {
|
|
Debug("Found Contention Resolution ID CE\n");
|
|
is_uecrid_successful = mac->contention_resolution_id_rcv(pending_mac_msg.get()->get_con_res_id());
|
|
}
|
|
}
|
|
|
|
pending_mac_msg.reset();
|
|
|
|
Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n");
|
|
|
|
pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH);
|
|
} else {
|
|
Warning("Trying to push PDU with payload size zero\n");
|
|
}
|
|
}
|
|
|
|
/* Demultiplexing of logical channels and dissassemble of MAC CE
|
|
* This function enqueues the packet and returns quickly because ACK
|
|
* deadline is important here.
|
|
*/
|
|
void demux::push_pdu(uint8_t* buff, uint32_t nof_bytes)
|
|
{
|
|
|
|
// Process Real-Time PDUs
|
|
process_sch_pdu_rt(buff, nof_bytes);
|
|
|
|
return pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH);
|
|
}
|
|
|
|
/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
|
|
* the MAC in transparent mode.
|
|
*/
|
|
void demux::push_pdu_bcch(uint8_t* buff, uint32_t nof_bytes)
|
|
{
|
|
pdus.push(buff, nof_bytes, srslte::pdu_queue::BCH);
|
|
}
|
|
|
|
void demux::push_pdu_mch(uint8_t* buff, uint32_t nof_bytes)
|
|
{
|
|
uint8_t *mch_buffer_ptr = request_buffer(nof_bytes);
|
|
memcpy(mch_buffer_ptr, buff, nof_bytes);
|
|
pdus.push(mch_buffer_ptr, nof_bytes, srslte::pdu_queue::MCH);
|
|
mch_buffer_ptr = NULL;
|
|
}
|
|
|
|
bool demux::process_pdus()
|
|
{
|
|
return pdus.process_pdus();
|
|
}
|
|
|
|
void demux::process_pdu(uint8_t* mac_pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel)
|
|
{
|
|
Debug("Processing MAC PDU channel %d\n", channel);
|
|
switch(channel) {
|
|
case srslte::pdu_queue::DCH:
|
|
// Unpack DLSCH MAC PDU
|
|
mac_msg.init_rx(nof_bytes);
|
|
mac_msg.parse_packet(mac_pdu);
|
|
process_sch_pdu(&mac_msg);
|
|
pdus.deallocate(mac_pdu);
|
|
break;
|
|
case srslte::pdu_queue::BCH:
|
|
rlc->write_pdu_bcch_dlsch(mac_pdu, nof_bytes);
|
|
break;
|
|
case srslte::pdu_queue::MCH:
|
|
mch_mac_msg.init_rx(nof_bytes);
|
|
mch_mac_msg.parse_packet(mac_pdu);
|
|
deallocate(mac_pdu);
|
|
process_mch_pdu(&mch_mac_msg);
|
|
// Process downlink MCH
|
|
break;
|
|
}
|
|
}
|
|
|
|
void demux::process_sch_pdu_rt(uint8_t* buff, uint32_t nof_bytes)
|
|
{
|
|
srslte::sch_pdu mac_msg_rt(20);
|
|
|
|
mac_msg_rt.init_rx(nof_bytes);
|
|
mac_msg_rt.parse_packet(buff);
|
|
|
|
while (mac_msg_rt.next()) {
|
|
if (mac_msg_rt.get()->is_sdu()) {
|
|
// Ignore SDU
|
|
} else {
|
|
// Process MAC Control Element
|
|
if (!process_ce(mac_msg_rt.get())) {
|
|
Warning("Received Subheader with invalid or unknown LCID\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
|
|
{
|
|
while(pdu_msg->next()) {
|
|
if (pdu_msg->get()->is_sdu()) {
|
|
bool route_pdu = true;
|
|
if (pdu_msg->get()->get_sdu_lcid() == 0) {
|
|
uint8_t *x = pdu_msg->get()->get_sdu_ptr();
|
|
uint32_t sum = 0;
|
|
for (uint32_t i=0;i<pdu_msg->get()->get_payload_size();i++) {
|
|
sum += x[i];
|
|
}
|
|
if (sum == 0) {
|
|
route_pdu = false;
|
|
Warning("Received all zero PDU\n");
|
|
}
|
|
}
|
|
// Route logical channel
|
|
if (route_pdu) {
|
|
Info("Delivering PDU for lcid=%d, %d bytes\n",
|
|
pdu_msg->get()->get_sdu_lcid(),
|
|
pdu_msg->get()->get_payload_size());
|
|
if (pdu_msg->get()->get_payload_size() < MAX_PDU_LEN) {
|
|
rlc->write_pdu(pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_ptr(), pdu_msg->get()->get_payload_size());
|
|
} else {
|
|
char tmp[1024];
|
|
srslte_vec_sprint_hex(tmp, sizeof(tmp), pdu_msg->get()->get_sdu_ptr(), 32);
|
|
Error("PDU size %d exceeds maximum PDU buffer size, lcid=%d, hex=[%s]\n",
|
|
pdu_msg->get()->get_payload_size(), pdu_msg->get()->get_sdu_lcid(), tmp);
|
|
}
|
|
}
|
|
} else {
|
|
// Ignore MAC Control Element
|
|
}
|
|
}
|
|
}
|
|
void demux::process_mch_pdu(srslte::mch_pdu *mch_msg){
|
|
//disgarding headers that have already been processed
|
|
while(mch_msg->next()){
|
|
|
|
if(srslte::mch_subh::MCH_SCHED_INFO == mch_msg->get()->ce_type()){
|
|
uint16_t stop;
|
|
uint8_t lcid;
|
|
if(mch_msg->get()->get_next_mch_sched_info(&lcid, &stop)) {
|
|
Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", lcid, stop, phy_h->get_current_tti());
|
|
}
|
|
}
|
|
if(mch_msg->get()->is_sdu()) {
|
|
uint32_t lcid = mch_msg->get()->get_sdu_lcid();
|
|
|
|
if(lcid >= SRSLTE_N_MCH_LCIDS) {
|
|
Error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid);
|
|
return;
|
|
}
|
|
Debug("Wrote MCH LCID=%d to RLC\n", lcid);
|
|
if(1 == mch_lcids[lcid]) {
|
|
rlc->write_pdu_mch(lcid, mch_msg->get()->get_sdu_ptr(), mch_msg->get()->get_payload_size());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void demux::mch_start_rx(uint32_t lcid)
|
|
{
|
|
if(lcid < 32) {
|
|
Info("MCH Channel Setup: LCID=%d\n", lcid);
|
|
mch_lcids[lcid] = 1;
|
|
} else {
|
|
Error("MCH Channel Setup: invalid LCID=%d\n", lcid);
|
|
}
|
|
}
|
|
|
|
bool demux::process_ce(srslte::sch_subh *subh) {
|
|
uint32_t cc_idx = 0;
|
|
switch(subh->ce_type()) {
|
|
case srslte::sch_subh::CON_RES_ID:
|
|
// Do nothing
|
|
break;
|
|
case srslte::sch_subh::TA_CMD:
|
|
phy_h->set_timeadv(subh->get_ta_cmd());
|
|
Info("Received TA=%d\n", subh->get_ta_cmd());
|
|
// Start or restart timeAlignmentTimer only if running
|
|
if (time_alignment_timer->is_running()) {
|
|
time_alignment_timer->reset();
|
|
time_alignment_timer->run();
|
|
}
|
|
break;
|
|
case srslte::sch_subh::SCELL_ACTIVATION:
|
|
cc_idx = (uint32_t)subh->get_activation_deactivation_cmd();
|
|
phy_h->set_activation_deactivation_scell(cc_idx);
|
|
mac->reset_harq(cc_idx);
|
|
break;
|
|
case srslte::sch_subh::PADDING:
|
|
break;
|
|
default:
|
|
Error("MAC CE 0x%x not supported\n", subh->ce_type());
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|