mirror of https://github.com/pvnis/srsRAN_4G.git
adding mbms-gw and mch generation tables
parent
12c9f50ba9
commit
e4c3f0bc30
@ -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 <vector>
|
||||||
|
#include "srslte/common/common.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace srsue
|
||||||
|
|
||||||
|
#endif // SECURITY_H
|
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace srsue
|
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
/* 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.0.254
|
||||||
|
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,326 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 <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.255");
|
||||||
|
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");
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
version = msg->msg[0]>>4;
|
||||||
|
if(version !=4)
|
||||||
|
{
|
||||||
|
m_mbms_gw_log->warning("IPv6 not supported yet.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Replace Destination IP with broadcast address
|
||||||
|
memcpy(&msg->msg[16],&baddr,4);
|
||||||
|
|
||||||
|
//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->console("Sent %d Bytes\n", msg->N_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} //namespace srsepc
|
Loading…
Reference in New Issue