mirror of https://github.com/pvnis/srsRAN_4G.git
Merge branch 'embms_merge_final' into next
commit
cb15dee3d4
@ -0,0 +1,52 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE 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.
|
||||
*
|
||||
* srsUE 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 GEN_MCH_TALBES_H
|
||||
#define GEN_MCH_TALBES_H
|
||||
|
||||
/******************************************************************************
|
||||
* Common mch table generation - used in phch_common of UE and ENB for MBMS
|
||||
*****************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
void generate_frame_mch_table(uint8_t *table, uint8_t alloc);
|
||||
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames);
|
||||
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#endif // SECURITY_H
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE 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.
|
||||
*
|
||||
* srsUE 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 "srslte/common/gen_mch_tables.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Key Generation
|
||||
*****************************************************************************/
|
||||
|
||||
void generate_frame_table(uint8_t *table, uint8_t alloc)
|
||||
{
|
||||
table[1] = (alloc >> 5) & 0x01;
|
||||
table[2] = (alloc >> 4) & 0x01;
|
||||
table[3] = (alloc >> 3) & 0x01;
|
||||
table[6] = (alloc >> 2) & 0x01;
|
||||
table[7] = (alloc >> 1) & 0x01;
|
||||
table[8] = (alloc >> 0) & 0x01;
|
||||
}
|
||||
|
||||
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames)
|
||||
{
|
||||
if(num_frames == 1){
|
||||
uint8_t alloc = (sf_alloc) & 0x3F;
|
||||
generate_frame_table(table, alloc);
|
||||
} else if(num_frames == 4){
|
||||
for(uint32_t j=0; j<4; j++){
|
||||
uint8_t alloc = (sf_alloc >> 6*(3-j)) & 0x3F;
|
||||
generate_frame_table(&table[j*10], alloc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc)
|
||||
{
|
||||
uint8_t alloc = (sf_alloc) & 0x3F;
|
||||
generate_frame_table(table, alloc);
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE 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.
|
||||
*
|
||||
* srsUE 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 <assert.h>
|
||||
#include "srslte/asn1/liblte_rrc.h"
|
||||
#include "srslte/common/log_filter.h"
|
||||
#include "srslte/phy/utils/bit.h"
|
||||
|
||||
void pack_test()
|
||||
{
|
||||
srslte::log_filter log1("RRC");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(1024);
|
||||
|
||||
uint32_t known_reference_len = 30;
|
||||
uint8_t known_reference[256] = {0x0d, 0x8f, 0xdf, 0xff, 0xff, 0xff, 0xe2, 0x2f,
|
||||
0xfc, 0x38, 0x5e, 0x61, 0xec, 0xa8, 0x00, 0x00,
|
||||
0x02, 0x02, 0x10, 0x00, 0x20, 0x05, 0xe6, 0x1e,
|
||||
0xca, 0x80, 0x00, 0x00, 0x40, 0x42};
|
||||
|
||||
LIBLTE_BYTE_MSG_STRUCT byte_buf;
|
||||
LIBLTE_BIT_MSG_STRUCT bit_buf;
|
||||
LIBLTE_RRC_MCCH_MSG_STRUCT mcch_msg;
|
||||
|
||||
mcch_msg.commonsf_allocpatternlist_r9_size = 2;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_offset = 4;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N32;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc = 0x3F;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_offset = 7;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N8;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR;
|
||||
mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc = 0xFFFFFF;
|
||||
|
||||
mcch_msg.commonsf_allocperiod_r9 = LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256;
|
||||
|
||||
mcch_msg.pmch_infolist_r9_size = 2;
|
||||
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size = 1;
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].logicalchannelid_r9 = 1;
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9_present = true;
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9 = 1;
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit = true;
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc = 0xF987;
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc = 0xF654;
|
||||
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 = 1;
|
||||
mcch_msg.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9 = 16;
|
||||
mcch_msg.pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024;
|
||||
mcch_msg.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9 = 1535;
|
||||
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9_size = 1;
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].logicalchannelid_r9 = 2;
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9_present = true;
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9 = 2;
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit = true;
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc = 0xF987;
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc = 0xF654;
|
||||
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 = 2;
|
||||
mcch_msg.pmch_infolist_r9[1].pmch_config_r9.datamcs_r9 = 8;
|
||||
mcch_msg.pmch_infolist_r9[1].pmch_config_r9.mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8;
|
||||
mcch_msg.pmch_infolist_r9[1].pmch_config_r9.sf_alloc_end_r9 = 0;
|
||||
|
||||
liblte_rrc_pack_mcch_msg(&mcch_msg, &bit_buf);
|
||||
liblte_pack(bit_buf.msg, bit_buf.N_bits, byte_buf.msg);
|
||||
byte_buf.N_bytes = (bit_buf.N_bits+7)/8;
|
||||
|
||||
//log1.info_hex(byte_buf.msg, byte_buf.N_bytes, "MCCH packed message:");
|
||||
|
||||
assert(byte_buf.N_bytes == known_reference_len);
|
||||
for(uint32 i=0; i<known_reference_len; i++) {
|
||||
assert(byte_buf.msg[i] == known_reference[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void unpack_test()
|
||||
{
|
||||
uint32_t known_reference_len = 30;
|
||||
uint8_t known_reference[256] = {0x0d, 0x8f, 0xdf, 0xff, 0xff, 0xff, 0xe2, 0x2f,
|
||||
0xfc, 0x38, 0x5e, 0x61, 0xec, 0xa8, 0x00, 0x00,
|
||||
0x02, 0x02, 0x10, 0x00, 0x20, 0x05, 0xe6, 0x1e,
|
||||
0xca, 0x80, 0x00, 0x00, 0x40, 0x42};
|
||||
|
||||
LIBLTE_BYTE_MSG_STRUCT byte_buf;
|
||||
LIBLTE_BIT_MSG_STRUCT bit_buf;
|
||||
LIBLTE_RRC_MCCH_MSG_STRUCT mcch_msg;
|
||||
|
||||
liblte_unpack(known_reference, known_reference_len, bit_buf.msg);
|
||||
bit_buf.N_bits = known_reference_len*8;
|
||||
liblte_rrc_unpack_mcch_msg(&bit_buf, &mcch_msg);
|
||||
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9_size == 2);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_offset == 4);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_period == LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N32);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc_num_frames == LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc == 0x3F);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_offset == 7);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_period == LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N8);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc_num_frames == LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR);
|
||||
assert(mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc == 0xFFFFFF);
|
||||
|
||||
assert(mcch_msg.commonsf_allocperiod_r9 == LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256);
|
||||
|
||||
assert(mcch_msg.pmch_infolist_r9_size == 2);
|
||||
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size == 1);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].logicalchannelid_r9 == 1);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9_present == true);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9 == 1);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit == true);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc == 0xF987);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc == 0xF654);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 == 1);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9 == 16);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9 == LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024);
|
||||
assert(mcch_msg.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9 == 1535);
|
||||
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9_size == 1);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].logicalchannelid_r9 == 2);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9_present == true);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9 == 2);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit == true);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc == 0xF987);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc == 0xF654);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 == 2);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].pmch_config_r9.datamcs_r9 == 8);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].pmch_config_r9.mch_schedulingperiod_r9 == LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8);
|
||||
assert(mcch_msg.pmch_infolist_r9[1].pmch_config_r9.sf_alloc_end_r9 == 0);
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pack_test();
|
||||
unpack_test();
|
||||
}
|
||||
|
@ -0,0 +1,91 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE 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.
|
||||
*
|
||||
* srsUE 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 <assert.h>
|
||||
#include <iostream>
|
||||
#include <srslte/srslte.h>
|
||||
#include "srslte/common/log_filter.h"
|
||||
#include "srslte/asn1/liblte_rrc.h"
|
||||
|
||||
|
||||
void basic_test() {
|
||||
srslte::log_filter log1("RRC");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(128);
|
||||
|
||||
LIBLTE_BIT_MSG_STRUCT bit_buf;
|
||||
LIBLTE_BIT_MSG_STRUCT bit_buf2;
|
||||
LIBLTE_BYTE_MSG_STRUCT byte_buf;
|
||||
LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg;
|
||||
|
||||
uint32_t rrc_message_len = 18;
|
||||
uint8_t rrc_message[] = {0x08, 0x10, 0x49, 0x3C, 0x0D, 0x97, 0x89, 0x83,
|
||||
0xC0, 0x84, 0x20, 0x82, 0x08, 0x21, 0x00, 0x01,
|
||||
0xBC, 0x48};
|
||||
|
||||
srslte_bit_unpack_vector(rrc_message, bit_buf.msg, rrc_message_len*8);
|
||||
bit_buf.N_bits = rrc_message_len*8;
|
||||
liblte_rrc_unpack_ul_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &ul_dcch_msg);
|
||||
|
||||
assert(ul_dcch_msg.msg_type == LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT);
|
||||
LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *rep = &ul_dcch_msg.msg.measurement_report;
|
||||
assert(rep->meas_id == 1);
|
||||
assert(rep->pcell_rsrp_result == 73);
|
||||
assert(rep->pcell_rsrq_result == 15);
|
||||
assert(rep->have_meas_result_neigh_cells);
|
||||
assert(rep->meas_result_neigh_cells_choice == LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA);
|
||||
LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA_STRUCT *eutra = &rep->meas_result_neigh_cells.eutra;
|
||||
assert(eutra->n_result == 1);
|
||||
assert(eutra->result_eutra_list[0].phys_cell_id == 357);
|
||||
assert(eutra->result_eutra_list[0].have_cgi_info);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mcc == 0xF898);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mnc == 0xFF78);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.cell_id == 0x1084104);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.tracking_area_code == 0x1042);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.n_plmn_identity_list == 1);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mcc == 0xFFFF);
|
||||
assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mnc == 0xFF00);
|
||||
assert(eutra->result_eutra_list[0].meas_result.have_rsrp);
|
||||
assert(eutra->result_eutra_list[0].meas_result.rsrp_result == 60);
|
||||
assert(eutra->result_eutra_list[0].meas_result.have_rsrp);
|
||||
assert(eutra->result_eutra_list[0].meas_result.rsrq_result == 18);
|
||||
|
||||
liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf2);
|
||||
srslte_bit_pack_vector(bit_buf2.msg, byte_buf.msg, bit_buf2.N_bits);
|
||||
byte_buf.N_bytes = (bit_buf2.N_bits+7)/8;
|
||||
log1.info_hex(byte_buf.msg, byte_buf.N_bytes, "UL_DCCH Packed message\n");
|
||||
|
||||
for(uint32_t i=0; i<rrc_message_len; i++) {
|
||||
assert(byte_buf.msg[i] == rrc_message[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
basic_test();
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
*
|
||||
* \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/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: mbms-gw.h
|
||||
* Description: Top-level MBMS-GW class. Creates and links all
|
||||
* interfaces and helpers.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MBMS_GW_H
|
||||
#define MBMS_GW_H
|
||||
|
||||
#include <cstddef>
|
||||
#include "srslte/common/log.h"
|
||||
#include "srslte/common/logger_file.h"
|
||||
#include "srslte/common/log_filter.h"
|
||||
#include "srslte/common/buffer_pool.h"
|
||||
#include "srslte/common/threads.h"
|
||||
#include "srslte/asn1/gtpc.h"
|
||||
|
||||
namespace srsepc{
|
||||
|
||||
|
||||
const uint16_t GTPU_RX_PORT = 2152;
|
||||
|
||||
typedef struct {
|
||||
std::string name;
|
||||
std::string sgi_mb_if_addr;
|
||||
std::string m1u_multi_addr;
|
||||
} mbms_gw_args_t;
|
||||
|
||||
struct pseudo_hdr
|
||||
{
|
||||
uint32_t src_addr;
|
||||
uint32_t dst_addr;
|
||||
uint8_t placeholder;
|
||||
uint8_t protocol;
|
||||
uint16_t udp_len;
|
||||
};
|
||||
|
||||
class mbms_gw:
|
||||
public thread
|
||||
{
|
||||
public:
|
||||
static mbms_gw* get_instance(void);
|
||||
static void cleanup(void);
|
||||
int init(mbms_gw_args_t* args, srslte::log_filter *mbms_gw_log);
|
||||
void stop();
|
||||
void run_thread();
|
||||
|
||||
private:
|
||||
|
||||
/* Methods */
|
||||
mbms_gw();
|
||||
virtual ~mbms_gw();
|
||||
static mbms_gw *m_instance;
|
||||
|
||||
srslte::error_t init_sgi_mb_if(mbms_gw_args_t *args);
|
||||
srslte::error_t init_m1_u(mbms_gw_args_t *args);
|
||||
void handle_sgi_md_pdu(srslte::byte_buffer_t *msg);
|
||||
uint16_t in_cksum(uint16_t *iphdr, int count);
|
||||
|
||||
/* Members */
|
||||
bool m_running;
|
||||
srslte::byte_buffer_pool *m_pool;
|
||||
srslte::log_filter *m_mbms_gw_log;
|
||||
|
||||
bool m_sgi_mb_up;
|
||||
int m_sgi_mb_if;
|
||||
|
||||
bool m_m1u_up;
|
||||
int m_m1u;
|
||||
struct sockaddr_in m_m1u_multi_addr;
|
||||
};
|
||||
|
||||
} // namespace srsepc
|
||||
|
||||
#endif // SGW_H
|
@ -0,0 +1,39 @@
|
||||
#####################################################################
|
||||
# srsEPC configuration file
|
||||
#####################################################################
|
||||
|
||||
#####################################################################
|
||||
# MBMS-GW configuration
|
||||
#
|
||||
# name: MBMS-GW name
|
||||
# sgi_mb_if_addr: SGi-mb interface IP address
|
||||
# m1u_addr: Multicast group for eNBs (FIXME this should be setup with M2/M3)
|
||||
#
|
||||
#####################################################################
|
||||
[mbms_gw]
|
||||
name = srsmbmsgw01
|
||||
sgi_mb_if_addr = 172.16.1.1
|
||||
m1u_multi_addr = 239.255.0.1
|
||||
|
||||
####################################################################
|
||||
# Log configuration
|
||||
#
|
||||
# Log levels can be set for individual layers. "all_level" sets log
|
||||
# level for all layers unless otherwise configured.
|
||||
# Format: e.g. s1ap_level = info
|
||||
#
|
||||
# In the same way, packet hex dumps can be limited for each level.
|
||||
# "all_hex_limit" sets the hex limit for all layers unless otherwise
|
||||
# configured.
|
||||
# Format: e.g. s1ap_hex_limit = 32
|
||||
#
|
||||
# Logging layers: mbms_gw, all
|
||||
# Logging levels: debug, info, warning, error, none
|
||||
#
|
||||
# filename: File path to use for log output. Can be set to stdout
|
||||
# to print logs to standard output
|
||||
#####################################################################
|
||||
[log]
|
||||
all_level = debug
|
||||
all_hex_limit = 32
|
||||
filename = /tmp/mbms.log
|
@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright 2013-2017 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/.
|
||||
#
|
||||
|
||||
file(GLOB SOURCES "*.cc")
|
||||
add_library(srsepc_mbms_gw STATIC ${SOURCES})
|
||||
install(TARGETS srsepc_mbms_gw DESTINATION ${LIBRARY_DIR})
|
@ -0,0 +1,216 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* \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 <iostream>
|
||||
#include <fstream>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "srsepc/hdr/mbms-gw/mbms-gw.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace srsepc;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
bool running = true;
|
||||
|
||||
void
|
||||
sig_int_handler(int signo){
|
||||
running = false;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
std::string mbms_gw_level;
|
||||
int mbms_gw_hex_limit;
|
||||
std::string all_level;
|
||||
int all_hex_limit;
|
||||
std::string filename;
|
||||
}log_args_t;
|
||||
|
||||
typedef struct {
|
||||
mbms_gw_args_t mbms_gw_args;
|
||||
log_args_t log_args;
|
||||
}all_args_t;
|
||||
|
||||
srslte::LOG_LEVEL_ENUM
|
||||
level(std::string l)
|
||||
{
|
||||
boost::to_upper(l);
|
||||
if("NONE" == l){
|
||||
return srslte::LOG_LEVEL_NONE;
|
||||
}else if("ERROR" == l){
|
||||
return srslte::LOG_LEVEL_ERROR;
|
||||
}else if("WARNING" == l){
|
||||
return srslte::LOG_LEVEL_WARNING;
|
||||
}else if("INFO" == l){
|
||||
return srslte::LOG_LEVEL_INFO;
|
||||
}else if("DEBUG" == l){
|
||||
return srslte::LOG_LEVEL_DEBUG;
|
||||
}else{
|
||||
return srslte::LOG_LEVEL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Program arguments processing
|
||||
***********************************************************************/
|
||||
string config_file;
|
||||
|
||||
void
|
||||
parse_args(all_args_t *args, int argc, char* argv[]) {
|
||||
|
||||
string mbms_gw_name;
|
||||
string mbms_gw_sgi_mb_if_addr;
|
||||
string mbms_gw_m1u_multi_addr;
|
||||
|
||||
string log_filename;
|
||||
|
||||
// Command line only options
|
||||
bpo::options_description general("General options");
|
||||
general.add_options()
|
||||
("help,h", "Produce help message")
|
||||
("version,v", "Print version information and exit")
|
||||
;
|
||||
|
||||
// Command line or config file options
|
||||
bpo::options_description common("Configuration options");
|
||||
common.add_options()
|
||||
|
||||
("mbms_gw.name", bpo::value<string>(&mbms_gw_name)->default_value("srsmbmsgw01"), "MBMS-GW Name")
|
||||
("mbms_gw.sgi_mb_if_addr", bpo::value<string>(&mbms_gw_sgi_mb_if_addr)->default_value("172.16.1.1"), "SGi-mb TUN interface Address")
|
||||
("mbms_gw.m1u_multi_addr", bpo::value<string>(&mbms_gw_m1u_multi_addr)->default_value("239.255.0.1"), "M1-u GTPu destination multicast address")
|
||||
|
||||
("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level")
|
||||
("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
|
||||
|
||||
("log.filename", bpo::value<string>(&args->log_args.filename)->default_value("/tmp/mbms.log"),"Log filename")
|
||||
;
|
||||
|
||||
// Positional options - config file location
|
||||
bpo::options_description position("Positional options");
|
||||
position.add_options()
|
||||
("config_file", bpo::value< string >(&config_file), "MBMS-GW configuration file")
|
||||
;
|
||||
bpo::positional_options_description p;
|
||||
p.add("config_file", -1);
|
||||
|
||||
// these options are allowed on the command line
|
||||
bpo::options_description cmdline_options;
|
||||
cmdline_options.add(common).add(position).add(general);
|
||||
|
||||
// parse the command line and store result in vm
|
||||
bpo::variables_map vm;
|
||||
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
|
||||
bpo::notify(vm);
|
||||
|
||||
// help option was given - print usage and exit
|
||||
if (vm.count("help")) {
|
||||
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
|
||||
cout << common << endl << general << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//Parsing Config File
|
||||
if (!vm.count("config_file")) {
|
||||
cout << "Error: Configuration file not provided" << endl;
|
||||
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
|
||||
exit(0);
|
||||
} else {
|
||||
cout << "Reading configuration file " << config_file << "..." << endl;
|
||||
ifstream conf(config_file.c_str(), ios::in);
|
||||
if(conf.fail()) {
|
||||
cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
|
||||
exit(1);
|
||||
}
|
||||
bpo::store(bpo::parse_config_file(conf, common), vm);
|
||||
bpo::notify(vm);
|
||||
}
|
||||
|
||||
args->mbms_gw_args.name = mbms_gw_name;
|
||||
args->mbms_gw_args.sgi_mb_if_addr = mbms_gw_sgi_mb_if_addr;
|
||||
args->mbms_gw_args.m1u_multi_addr = mbms_gw_m1u_multi_addr;
|
||||
// Apply all_level to any unset layers
|
||||
if (vm.count("log.all_level")) {
|
||||
if(!vm.count("log.mbms_gw_level")) {
|
||||
args->log_args.mbms_gw_level = args->log_args.all_level;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply all_hex_limit to any unset layers
|
||||
if (vm.count("log.all_hex_limit")) {
|
||||
if(!vm.count("log.mbms_gw_hex_limit")) {
|
||||
args->log_args.mbms_gw_hex_limit = args->log_args.all_hex_limit;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc,char * argv[] )
|
||||
{
|
||||
cout << endl <<"--- Software Radio Systems MBMS ---" << endl << endl;
|
||||
signal(SIGINT, sig_int_handler);
|
||||
signal(SIGTERM, sig_int_handler);
|
||||
signal(SIGKILL, sig_int_handler);
|
||||
|
||||
all_args_t args;
|
||||
parse_args(&args, argc, argv);
|
||||
|
||||
srslte::logger_stdout logger_stdout;
|
||||
srslte::logger_file logger_file;
|
||||
srslte::logger *logger;
|
||||
|
||||
/*Init logger*/
|
||||
if (!args.log_args.filename.compare("stdout")) {
|
||||
logger = &logger_stdout;
|
||||
} else {
|
||||
logger_file.init(args.log_args.filename);
|
||||
logger_file.log("\n--- Software Radio Systems MBMS log ---\n\n");
|
||||
logger = &logger_file;
|
||||
}
|
||||
|
||||
srslte::log_filter mbms_gw_log;
|
||||
mbms_gw_log.init("MBMS",logger);
|
||||
mbms_gw_log.set_level(level(args.log_args.mbms_gw_level));
|
||||
mbms_gw_log.set_hex_limit(args.log_args.mbms_gw_hex_limit);
|
||||
|
||||
mbms_gw *mbms_gw = mbms_gw::get_instance();
|
||||
if(mbms_gw->init(&args.mbms_gw_args,&mbms_gw_log)) {
|
||||
cout << "Error initializing MBMS-GW" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mbms_gw->start();
|
||||
while(running) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
mbms_gw->stop();
|
||||
mbms_gw->cleanup();
|
||||
|
||||
cout << std::endl <<"--- exiting ---" << endl;
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,385 @@
|
||||
/**
|
||||
*
|
||||
* \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 <iostream>
|
||||
#include <algorithm>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <linux/ip.h>
|
||||
#include "srsepc/hdr/mbms-gw/mbms-gw.h"
|
||||
#include "srslte/upper/gtpu.h"
|
||||
|
||||
namespace srsepc{
|
||||
|
||||
mbms_gw* mbms_gw::m_instance = NULL;
|
||||
pthread_mutex_t mbms_gw_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
const uint16_t MBMS_GW_BUFFER_SIZE = 2500;
|
||||
|
||||
mbms_gw::mbms_gw():
|
||||
m_running(false),
|
||||
m_sgi_mb_up(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mbms_gw::~mbms_gw()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mbms_gw*
|
||||
mbms_gw::get_instance(void)
|
||||
{
|
||||
pthread_mutex_lock(&mbms_gw_instance_mutex);
|
||||
if(NULL == m_instance) {
|
||||
m_instance = new mbms_gw();
|
||||
}
|
||||
pthread_mutex_unlock(&mbms_gw_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
void
|
||||
mbms_gw::cleanup(void)
|
||||
{
|
||||
pthread_mutex_lock(&mbms_gw_instance_mutex);
|
||||
if(NULL != m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&mbms_gw_instance_mutex);
|
||||
}
|
||||
|
||||
int
|
||||
mbms_gw::init(mbms_gw_args_t* args, srslte::log_filter *mbms_gw_log)
|
||||
{
|
||||
srslte::error_t err;
|
||||
m_pool = srslte::byte_buffer_pool::get_instance();
|
||||
|
||||
//Init log
|
||||
m_mbms_gw_log = mbms_gw_log;
|
||||
|
||||
err = init_sgi_mb_if(args);
|
||||
if (err != srslte::ERROR_NONE)
|
||||
{
|
||||
m_mbms_gw_log->console("Error initializing SGi-MB.\n");
|
||||
m_mbms_gw_log->error("Error initializing SGi-MB.\n");
|
||||
return -1;
|
||||
}
|
||||
err = init_m1_u(args);
|
||||
if (err != srslte::ERROR_NONE)
|
||||
{
|
||||
m_mbms_gw_log->console("Error initializing SGi-MB.\n");
|
||||
m_mbms_gw_log->error("Error initializing SGi-MB.\n");
|
||||
return -1;
|
||||
}
|
||||
m_mbms_gw_log->info("MBMS GW Initiated\n");
|
||||
m_mbms_gw_log->console("MBMS GW Initiated\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
mbms_gw::stop()
|
||||
{
|
||||
if(m_running)
|
||||
{
|
||||
if(m_sgi_mb_up)
|
||||
{
|
||||
close(m_sgi_mb_if);
|
||||
m_mbms_gw_log->info("Closed SGi-MB interface\n");
|
||||
}
|
||||
m_running = false;
|
||||
thread_cancel();
|
||||
wait_thread_finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
srslte::error_t
|
||||
mbms_gw::init_sgi_mb_if(mbms_gw_args_t *args)
|
||||
{
|
||||
char dev[IFNAMSIZ] = "sgi_mb";
|
||||
struct ifreq ifr;
|
||||
|
||||
if(m_sgi_mb_up)
|
||||
{
|
||||
return(srslte::ERROR_ALREADY_STARTED);
|
||||
}
|
||||
|
||||
|
||||
// Construct the TUN device
|
||||
m_sgi_mb_if = open("/dev/net/tun", O_RDWR);
|
||||
m_mbms_gw_log->info("TUN file descriptor = %d\n", m_sgi_mb_if);
|
||||
if(m_sgi_mb_if < 0)
|
||||
{
|
||||
m_mbms_gw_log->error("Failed to open TUN device: %s\n", strerror(errno));
|
||||
return(srslte::ERROR_CANT_START);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
|
||||
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0';
|
||||
|
||||
if(ioctl(m_sgi_mb_if, TUNSETIFF, &ifr) < 0)
|
||||
{
|
||||
m_mbms_gw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
|
||||
close(m_sgi_mb_if);
|
||||
return(srslte::ERROR_CANT_START);
|
||||
}
|
||||
|
||||
// Bring up the interface
|
||||
int sgi_mb_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sgi_mb_sock<0)
|
||||
{
|
||||
m_mbms_gw_log->error("Failed to bring up socket: %s\n", strerror(errno));
|
||||
close(m_sgi_mb_if);
|
||||
return(srslte::ERROR_CANT_START);
|
||||
}
|
||||
|
||||
if(ioctl(sgi_mb_sock, SIOCGIFFLAGS, &ifr) < 0)
|
||||
{
|
||||
m_mbms_gw_log->error("Failed to bring up interface: %s\n", strerror(errno));
|
||||
close(m_sgi_mb_if);
|
||||
close(sgi_mb_sock);
|
||||
return(srslte::ERROR_CANT_START);
|
||||
}
|
||||
|
||||
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
|
||||
if(ioctl(sgi_mb_sock, SIOCSIFFLAGS, &ifr) < 0)
|
||||
{
|
||||
m_mbms_gw_log->error("Failed to set socket flags: %s\n", strerror(errno));
|
||||
close(sgi_mb_sock);
|
||||
close(m_sgi_mb_if);
|
||||
return(srslte::ERROR_CANT_START);
|
||||
}
|
||||
|
||||
//Set IP of the interface
|
||||
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr.ifr_addr;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = inet_addr(args->sgi_mb_if_addr.c_str());
|
||||
addr->sin_port = 0;
|
||||
|
||||
if (ioctl(sgi_mb_sock, SIOCSIFADDR, &ifr) < 0) {
|
||||
m_mbms_gw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_mb_if_addr.c_str(), strerror(errno));
|
||||
close(m_sgi_mb_if);
|
||||
close(sgi_mb_sock);
|
||||
return srslte::ERROR_CANT_START;
|
||||
}
|
||||
|
||||
ifr.ifr_netmask.sa_family = AF_INET;
|
||||
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
|
||||
if (ioctl(sgi_mb_sock, SIOCSIFNETMASK, &ifr) < 0) {
|
||||
m_mbms_gw_log->error("Failed to set TUN interface Netmask. Error: %s\n", strerror(errno));
|
||||
close(m_sgi_mb_if);
|
||||
close(sgi_mb_sock);
|
||||
return srslte::ERROR_CANT_START;
|
||||
}
|
||||
|
||||
m_sgi_mb_up = true;
|
||||
close(sgi_mb_sock);
|
||||
return(srslte::ERROR_NONE);
|
||||
}
|
||||
|
||||
srslte::error_t
|
||||
mbms_gw::init_m1_u(mbms_gw_args_t *args)
|
||||
{
|
||||
int addrlen;
|
||||
struct sockaddr_in addr;
|
||||
m_m1u = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(m_m1u<0)
|
||||
{
|
||||
m_mbms_gw_log->error("Failed to open socket: %s\n", strerror(errno));
|
||||
return srslte::ERROR_CANT_START;
|
||||
}
|
||||
m_m1u_up = true;
|
||||
|
||||
/* set no loopback */
|
||||
char loopch = 0;
|
||||
if(setsockopt(m_m1u, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&loopch, sizeof(char))<0){
|
||||
m_mbms_gw_log->error("Failed to disable loopback: %s\n", strerror(errno));
|
||||
return srslte::ERROR_CANT_START;
|
||||
} else {
|
||||
m_mbms_gw_log->debug("Loopback disabled\n");
|
||||
}
|
||||
|
||||
/* Set local interface for outbound multicast packets*/
|
||||
/* The IP must be associated with a local multicast capable interface */
|
||||
struct in_addr local_if;
|
||||
local_if.s_addr = inet_addr("127.0.1.200");
|
||||
if(setsockopt(m_m1u, IPPROTO_IP, IP_MULTICAST_IF, (char*)&local_if, sizeof(struct in_addr))<0){
|
||||
perror("Error setting multicast interface.\n");
|
||||
} else {
|
||||
printf("Multicast interface specified.\n");
|
||||
}
|
||||
|
||||
bzero(&m_m1u_multi_addr,sizeof(m_m1u_multi_addr));
|
||||
m_m1u_multi_addr.sin_family = AF_INET;
|
||||
m_m1u_multi_addr.sin_port = htons(GTPU_RX_PORT+1);
|
||||
m_m1u_multi_addr.sin_addr.s_addr = inet_addr(args->m1u_multi_addr.c_str());
|
||||
m_mbms_gw_log->info("Initialized M1-U\n");
|
||||
|
||||
return srslte::ERROR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
mbms_gw::run_thread()
|
||||
{
|
||||
//Mark the thread as running
|
||||
m_running=true;
|
||||
srslte::byte_buffer_t *msg;
|
||||
msg = m_pool->allocate();
|
||||
|
||||
|
||||
uint8_t seq = 0;
|
||||
while(m_running)
|
||||
{
|
||||
msg->reset();
|
||||
int n;
|
||||
do{
|
||||
n = read(m_sgi_mb_if, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES);
|
||||
}while(n == -1 && errno == EAGAIN);
|
||||
|
||||
if(n<0){
|
||||
m_mbms_gw_log->error("Error reading from TUN interface. Error: %s\n", strerror(errno));
|
||||
}
|
||||
else{
|
||||
msg->N_bytes = n;
|
||||
handle_sgi_md_pdu(msg);
|
||||
}
|
||||
}
|
||||
m_pool->deallocate(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
mbms_gw::handle_sgi_md_pdu(srslte::byte_buffer_t *msg)
|
||||
{
|
||||
uint8_t version;
|
||||
srslte::gtpu_header_t header;
|
||||
in_addr_t baddr = inet_addr("172.16.0.255");
|
||||
in_addr_t saddr = inet_addr("172.16.0.254");
|
||||
|
||||
//Setup GTP-U header
|
||||
header.flags = 0x30;
|
||||
header.message_type = 0xFF;
|
||||
header.length = msg->N_bytes;
|
||||
header.teid = 0xAAAA; //FIXME Harcoded TEID for now
|
||||
|
||||
//Sanity Check IP packet
|
||||
if(msg->N_bytes < 20)
|
||||
{
|
||||
m_mbms_gw_log->error("IPv4 min len: %d, drop msg len %d\n", 20, msg->N_bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
//IP+UDP Headers
|
||||
struct iphdr *iph = (struct iphdr *) msg->msg;
|
||||
struct udphdr *udph = (struct udphdr *) (msg->msg + iph->ihl*4);
|
||||
if(iph->version != 4)
|
||||
{
|
||||
m_mbms_gw_log->warning("IPv6 not supported yet.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//Replace Destination IP with broadcast address
|
||||
iph->daddr = baddr;
|
||||
|
||||
//Replace Source IP with address in same subnet
|
||||
iph->saddr = saddr;
|
||||
|
||||
//Replace IP cheksum
|
||||
iph->check = 0;
|
||||
iph->check = in_cksum((uint16_t*)msg->msg,4*(msg->msg[0] & 0x0F));
|
||||
|
||||
//Set Pseudo Header
|
||||
struct pseudo_hdr phdr;
|
||||
phdr.src_addr = iph->saddr;
|
||||
phdr.dst_addr = iph->daddr;
|
||||
phdr.protocol = IPPROTO_UDP;
|
||||
phdr.placeholder = 0;
|
||||
phdr.udp_len = udph->len;
|
||||
|
||||
//Set Pseudo Datagram
|
||||
udph->check = 0;
|
||||
int psize = sizeof(struct pseudo_hdr) + ntohs(udph->len);
|
||||
uint8_t * pseudo_dgram = (uint8_t*) malloc(psize);
|
||||
memcpy(pseudo_dgram, &phdr,sizeof(struct pseudo_hdr));
|
||||
memcpy(pseudo_dgram+sizeof(pseudo_hdr),udph,ntohs(udph->len));
|
||||
|
||||
//Recompute UDP checksum
|
||||
udph->check = in_cksum((uint16_t*) pseudo_dgram, psize);
|
||||
free(pseudo_dgram);
|
||||
|
||||
//Write GTP-U header into packet
|
||||
if(!srslte::gtpu_write_header(&header, msg))
|
||||
{
|
||||
m_mbms_gw_log->console("Error writing GTP-U header on PDU\n");
|
||||
}
|
||||
|
||||
int n = sendto(m_m1u, msg->msg, msg->N_bytes, 0,
|
||||
(sockaddr *) &m_m1u_multi_addr, sizeof(struct sockaddr));
|
||||
if(n<0){
|
||||
m_mbms_gw_log->console("Error writting to M1-U socket.\n");
|
||||
}
|
||||
else{
|
||||
m_mbms_gw_log->debug("Sent %d Bytes\n", msg->N_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t
|
||||
mbms_gw::in_cksum(uint16_t *iphdr, int count)
|
||||
{
|
||||
|
||||
//RFC 1071
|
||||
uint32_t sum = 0;
|
||||
uint16_t padd = 0;
|
||||
uint16_t result;
|
||||
while(count > 1)
|
||||
{
|
||||
sum+= *iphdr++;
|
||||
count -= 2;
|
||||
}
|
||||
if( count > 0 )
|
||||
{
|
||||
padd = * (uint8_t *) iphdr;
|
||||
sum += padd;
|
||||
}
|
||||
/*Fold 32-bit sum to 16-bit*/
|
||||
// while(sum>>16)
|
||||
// sum = (sum & 0xffff) + (sum >> 16);
|
||||
sum = (sum>>16)+(sum & 0xFFFF);
|
||||
sum = sum + (sum >> 16);
|
||||
result = (uint16_t) ~sum;
|
||||
return result;
|
||||
}
|
||||
|
||||
} //namespace srsepc
|
Loading…
Reference in New Issue