Commit 55cbe314 authored by dukl's avatar dukl

amf by bupt stage1

parent fc70c11e

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

## amf configuration file
AMF =
{
INSTANCE_ID = 10;
PID_DIRECTORY = "/var/run";
######################################################################## NG SETUP RESPONSE IEs ############################################################
AMF_NAME = "bupt-amf";
ServedGUAMIList = (
{MCC = "460"; MNC = "11"; RegionID = "10"; AMFSetID = "1"; AMFPointer = "0"}, #48bits <MCC><MNC><RegionID><AMFSetID><AMFPointer>
{MCC = "460"; MNC = "11"; RegionID = "10"; AMFSetID = "1"; AMFPointer = "1"} #48bits <MCC><MNC><RegionID><AMFSetID><AMFPointer>
);
RelativeAMFCapacity = 10;
PLMNSupportList = (
{MCC = "460"; MNC = "11";
SliceSupportList = (
{SST = "1"; SD = "none"},
{SST = "1"; SD = "12"}
)
}
);
##################################################################### clause 9.2.6.2, 3gpp ts38.413 ####################################################
STATISTICS_TIMER_INTERVAL = 10; #second
INTERFACES:{
NGAP_AMF:{
INTERFACE_NAME = "ens18";
IPV4_ADDRESS = "read";
SCTP_PORT = 38412;
PPID = 60;
};
N11:{
SMF_INSTANCES_POOL = (
{SMF_INSTANCE_ID = 1; IPV4_ADDRESS = "10.103.238.20"},
{SMF_INSTANCE_ID = 2; IPV4_ADDRESS = "10.103.238.21"}
);
};
};
};
MODULES =
{
NGAP_MESSAGE = (
{MSG_NAME = "NGSetupRequest"; ProcedureCode = 21; TypeOfMessage = "initialMessage"}
);
};
## system modules, such as NGAP message modules and NAS message modules
MODULES =
{
NGAP_MESSAGE = (
{MSG_NAME = "NGSetupRequest"; ProcedureCode = 21; TypeOfMessage = "initialMessage"}
);
};
#include "amf_app.hpp"
#include "itti.hpp"
#include "ngap_app.hpp"
#include "amf_config.hpp"
#include "amf_n2.hpp"
#include "amf_n1.hpp"
#include <stdexcept>
#include <iostream>
#include <cstdlib>
#include "amf_statistics.hpp"
using namespace ngap;
using namespace amf;
using namespace config;
extern amf_app * amf_app_inst;
extern itti_mw * itti_inst;
amf_n2 * amf_n2_inst = nullptr;
amf_n1 * amf_n1_inst = nullptr;
extern amf_config amf_cfg;
extern statistics stacs;
void amf_app_task(void*);
amf_app::amf_app(const amf_config &amf_cfg){
Logger::amf_app().startup("Creating amf application functionality layer");
if(itti_inst->create_task(TASK_AMF_APP, amf_app_task, nullptr)){
Logger::amf_app().error( "Cannot create task TASK_AMF_APP" );
throw std::runtime_error( "Cannot create task TASK_AMF_APP" );
}
try{
amf_n2_inst = new amf_n2(std::string(inet_ntoa(amf_cfg.n2.addr4)),amf_cfg.n2.port);
}catch(std::exception& e){
Logger::amf_app().error( "Cannot create amf n2 interface: %s", e.what() );
throw;
}
try{
amf_n1_inst = new amf_n1();
}catch(std::exception& e){
Logger::amf_app().error( "Cannot create amf n1 interface: %s", e.what() );
}
timer_id_t tid = itti_inst->timer_setup(amf_cfg.statistics_interval,0,TASK_AMF_APP,TASK_AMF_APP_PERIODIC_STATISTICS,0);
Logger::amf_app().startup( "Started timer(%d)", tid);
}
void amf_app::allRegistredModulesInit(const amf_modules & modules){
Logger::amf_app().info("Initiating all registred modules");
}
void amf_app_task(void*){
const task_id_t task_id = TASK_AMF_APP;
itti_inst->notify_task_ready(task_id);
do {
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
timer_id_t tid;
switch(msg->msg_type){
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
switch(to->arg1_user){
case TASK_AMF_APP_PERIODIC_STATISTICS:
tid = itti_inst->timer_setup(amf_cfg.statistics_interval,0,TASK_AMF_APP,TASK_AMF_APP_PERIODIC_STATISTICS,0);
//Logger::amf_app().info("statistics(ready to be implemented)");
stacs.display();
break;
default:
Logger::amf_app().info( "no handler for timer(%d) with arg1_user(%d) ", to->timer_id, to->arg1_user);
}
}
break;
default:
Logger::amf_app().info( "no handler for msg type %d", msg->msg_type);
}
}while(true);
}
#ifndef _AMF_APP_H_
#define _AMF_APP_H_
#include <map>
#include <set>
#include <shared_mutex>
#include <string>
#include <thread>
#include "amf_config.hpp"
#include "amf_module_from_config.hpp"
using namespace config;
namespace amf{
#define TASK_AMF_APP_PERIODIC_STATISTICS (0)
class amf_app{
public:
explicit amf_app(const amf_config &amf_cfg);
amf_app(amf_app const&) = delete;
void operator=(amf_app const&) = delete;
void allRegistredModulesInit(const amf_modules & modules);
private:
};
}
#endif
#include "amf_config.hpp"
#include "logger.hpp"
#include <libconfig.h++>
#include "string.hpp"
#include "thread_sched.hpp"
#include "amf_app.hpp"
#include "if.hpp"
extern "C"{
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "common_defs.h"
}
#include <iostream>
using namespace libconfig;
using namespace std;
using namespace amf;
namespace config{
amf_config::amf_config(){
}
amf_config::~amf_config(){}
int amf_config::load(const std::string &config_file){
cout<<endl;
Logger::amf_app().debug("Load amf system configuration file(%s)",config_file.c_str());
Config cfg;
unsigned char buf_in6_addr[sizeof (struct in6_addr)];
try{
cfg.readFile(config_file.c_str());
}catch(const FileIOException &fioex){
Logger::amf_app().error("I/O error while reading file %s - %s", config_file.c_str(), fioex.what());
throw;
}catch(const ParseException &pex){
Logger::amf_app().error("Parse error at %s:%d - %s", pex.getFile(), pex.getLine(), pex.getError());
throw;
}
const Setting &root = cfg.getRoot();
try{
const Setting& amf_cfg = root[AMF_CONFIG_STRING_AMF_CONFIG];
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s", nfex.what(), nfex.getPath());
return -1;
}
const Setting &amf_cfg = root[AMF_CONFIG_STRING_AMF_CONFIG];
try{
amf_cfg.lookupValue(AMF_CONFIG_STRING_INSTANCE_ID, instance);
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try{
amf_cfg.lookupValue(AMF_CONFIG_STRING_STATISTICS_TIMER_INTERVAL, statistics_interval);
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try{
amf_cfg.lookupValue(AMF_CONFIG_STRING_PID_DIRECTORY, pid_dir);
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try{
amf_cfg.lookupValue(AMF_CONFIG_STRING_AMF_NAME, AMF_Name);
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try{
const Setting &guami_list_cfg = amf_cfg[AMF_CONFIG_STRING_ServedGUAMIList];
int count = guami_list_cfg.getLength();
for(int i=0;i<count;i++){
guami_t guami;
const Setting &guami_item = guami_list_cfg[i];
guami_item.lookupValue(AMF_CONFIG_STRING_MCC,guami.mcc);
guami_item.lookupValue(AMF_CONFIG_STRING_MNC,guami.mnc);
guami_item.lookupValue(AMF_CONFIG_STRING_RegionID,guami.regionID);
guami_item.lookupValue(AMF_CONFIG_STRING_AMFSetID,guami.AmfSetID);
guami_item.lookupValue(AMF_CONFIG_STRING_AMFPointer,guami.AmfPointer);
guami_list.push_back(guami);
}
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try{
amf_cfg.lookupValue(AMF_CONFIG_STRING_RelativeAMFCapacity, relativeAMFCapacity);
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try{
const Setting &plmn_list_cfg = amf_cfg[AMF_CONFIG_STRING_PLMNSupportList];
int count = plmn_list_cfg.getLength();
for(int i=0;i<count;i++){
plmn_item_t plmn_item;
const Setting & item = plmn_list_cfg[i];
item.lookupValue(AMF_CONFIG_STRING_MCC, plmn_item.mcc);
item.lookupValue(AMF_CONFIG_STRING_MNC, plmn_item.mnc);
const Setting &slice_list_cfg = plmn_list_cfg[i][AMF_CONFIG_STRING_SliceSupportList];
int numOfSlice = slice_list_cfg.getLength();
for(int j=0;j<numOfSlice;j++){
slice_t slice;
const Setting & slice_item = slice_list_cfg[j];
slice_item.lookupValue(AMF_CONFIG_STRING_SST, slice.sST);
slice_item.lookupValue(AMF_CONFIG_STRING_SD, slice.sD);
plmn_item.slice_list.push_back(slice);
}
plmn_list.push_back(plmn_item);
}
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try{
const Setting &new_if_cfg = amf_cfg[AMF_CONFIG_STRING_INTERFACES];
const Setting &n2_amf_cfg = new_if_cfg[AMF_CONFIG_STRING_INTERFACE_NGAP_AMF];
load_interface(n2_amf_cfg, n2);
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
return -1;
}
}
void amf_config::display(){
Logger::config().info( "======= BUPTv1.0 =======");
Logger::config().info( "Configuration AMF:");
Logger::config().info( "- Instance .......................: %d", instance);
Logger::config().info( "- PID dir ........................: %s", pid_dir.c_str());
Logger::config().info( "- AMF NAME........................: %s", AMF_Name.c_str());
Logger::config().info( "- ServedGUAMIList ................: ");
for(int i=0;i<guami_list.size();i++){
Logger::config().info( " [%s] [%s] [%s] [%s] [%s]", guami_list[i].mcc.c_str(),guami_list[i].mnc.c_str(),guami_list[i].regionID.c_str(),guami_list[i].AmfSetID.c_str(),guami_list[i].AmfPointer.c_str());
}
Logger::config().info( "- RelativeAMFCapacity ............: %d", relativeAMFCapacity);
Logger::config().info( "- PLMNSupportList ................: ");
for(int i=0;i<plmn_list.size();i++){
Logger::config().info( " [%s] [%s] ", plmn_list[i].mcc.c_str(),plmn_list[i].mnc.c_str());
Logger::config().info( " - SliceSupportList ............: ");
for(int j=0;j<plmn_list[i].slice_list.size();j++){
Logger::config().info( " [%s] [%s] ", plmn_list[i].slice_list[j].sST.c_str(),plmn_list[i].slice_list[j].sD.c_str());
}
}
}
int amf_config::load_interface(const libconfig::Setting& if_cfg, interface_cfg_t& cfg){
if_cfg.lookupValue(AMF_CONFIG_STRING_INTERFACE_NAME, cfg.if_name);
util::trim(cfg.if_name);
if (not boost::iequals(cfg.if_name, "none")) {
std::string address = {};
if_cfg.lookupValue(AMF_CONFIG_STRING_IPV4_ADDRESS, address);
util::trim(address);
if (boost::iequals(address, "read")) {
if (get_inet_addr_infos_from_iface(cfg.if_name, cfg.addr4, cfg.network4, cfg.mtu)) {
Logger::amf_app().error("Could not read %s network interface configuration", cfg.if_name);
return RETURNerror;
}
} else {
std::vector<std::string> words;
boost::split(words, address, boost::is_any_of("/"), boost::token_compress_on);
if (words.size() != 2) {
Logger::amf_app().error("Bad value " AMF_CONFIG_STRING_IPV4_ADDRESS " = %s in config file", address.c_str());
return RETURNerror;
}
unsigned char buf_in_addr[sizeof(struct in6_addr)]; // you never know...
if (inet_pton (AF_INET, util::trim(words.at(0)).c_str(), buf_in_addr) == 1) {
memcpy (&cfg.addr4, buf_in_addr, sizeof (struct in_addr));
} else {
Logger::amf_app().error("In conversion: Bad value " AMF_CONFIG_STRING_IPV4_ADDRESS " = %s in config file", util::trim(words.at(0)).c_str());
return RETURNerror;
}
cfg.network4.s_addr = htons(ntohs(cfg.addr4.s_addr) & 0xFFFFFFFF << (32 - std::stoi (util::trim(words.at(1)))));
}
if_cfg.lookupValue(AMF_CONFIG_STRING_SCTP_PORT, cfg.port);
try {
const Setting& sched_params_cfg = if_cfg[AMF_CONFIG_STRING_SCHED_PARAMS];
load_thread_sched_params(sched_params_cfg, cfg.thread_rd_sched_params);
} catch(const SettingNotFoundException &nfex) {
Logger::amf_app().error("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
}
return RETURNok;
}
int amf_config::load_thread_sched_params(const Setting& thread_sched_params_cfg, util::thread_sched_params& cfg)
{
try {
thread_sched_params_cfg.lookupValue(AMF_CONFIG_STRING_THREAD_RD_CPU_ID, cfg.cpu_id);
} catch(const SettingNotFoundException &nfex) {
Logger::amf_app().info("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try {
std::string thread_rd_sched_policy;
thread_sched_params_cfg.lookupValue(AMF_CONFIG_STRING_THREAD_RD_SCHED_POLICY, thread_rd_sched_policy);
util::trim(thread_rd_sched_policy);
if (boost::iequals(thread_rd_sched_policy, "SCHED_OTHER")) {
cfg.sched_policy = SCHED_OTHER;
} else if (boost::iequals(thread_rd_sched_policy, "SCHED_IDLE")) {
cfg.sched_policy = SCHED_IDLE;
} else if (boost::iequals(thread_rd_sched_policy, "SCHED_BATCH")) {
cfg.sched_policy = SCHED_BATCH;
} else if (boost::iequals(thread_rd_sched_policy, "SCHED_FIFO")) {
cfg.sched_policy = SCHED_FIFO;
} else if (boost::iequals(thread_rd_sched_policy, "SCHED_RR")) {
cfg.sched_policy = SCHED_RR;
} else {
Logger::amf_app().error("thread_rd_sched_policy: %s, unknown in config file", thread_rd_sched_policy.c_str());
return RETURNerror;
}
} catch(const SettingNotFoundException &nfex) {
Logger::amf_app().info("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try {
thread_sched_params_cfg.lookupValue(AMF_CONFIG_STRING_THREAD_RD_SCHED_PRIORITY, cfg.sched_priority);
if ((cfg.sched_priority > 99) || (cfg.sched_priority < 1)) {
Logger::amf_app().error("thread_rd_sched_priority: %d, must be in interval [1..99] in config file", cfg.sched_priority);
return RETURNerror;
}
} catch(const SettingNotFoundException &nfex) {
Logger::amf_app().info("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
return RETURNok;
}
}
#ifndef _AMF_CONFIG_H_
#define _AMF_CONFIG_H_
#include <arpa/inet.h>
#include <libconfig.h++>
#include <netinet/in.h>
#include <sys/socket.h>
#include <mutex>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include "amf_config.hpp"
#include "thread_sched.hpp"
#define AMF_CONFIG_STRING_AMF_CONFIG "AMF"
#define AMF_CONFIG_STRING_PID_DIRECTORY "PID_DIRECTORY"
#define AMF_CONFIG_STRING_INSTANCE_ID "INSTANCE_ID"
#define AMF_CONFIG_STRING_STATISTICS_TIMER_INTERVAL "STATISTICS_TIMER_INTERVAL"
#define AMF_CONFIG_STRING_INTERFACES "INTERFACES"
#define AMF_CONFIG_STRING_INTERFACE_NGAP_AMF "NGAP_AMF"
#define AMF_CONFIG_STRING_INTERFACE_NAME "INTERFACE_NAME"
#define AMF_CONFIG_STRING_IPV4_ADDRESS "IPV4_ADDRESS"
#define AMF_CONFIG_STRING_SCTP_PORT "SCTP_PORT"
#define AMF_CONFIG_STRING_PPID "PPID"
#define AMF_CONFIG_STRING_SCHED_PARAMS "SCHED_PARAMS"
#define AMF_CONFIG_STRING_THREAD_RD_CPU_ID "CPU_ID"
#define AMF_CONFIG_STRING_THREAD_RD_SCHED_POLICY "SCHED_POLICY"
#define AMF_CONFIG_STRING_THREAD_RD_SCHED_PRIORITY "SCHED_PRIORITY"
#define AMF_CONFIG_STRING_AMF_NAME "AMF_NAME"
#define AMF_CONFIG_STRING_ServedGUAMIList "ServedGUAMIList"
#define AMF_CONFIG_STRING_MCC "MCC"
#define AMF_CONFIG_STRING_MNC "MNC"
#define AMF_CONFIG_STRING_RegionID "RegionID"
#define AMF_CONFIG_STRING_AMFSetID "AMFSetID"
#define AMF_CONFIG_STRING_AMFPointer "AMFPointer"
#define AMF_CONFIG_STRING_RelativeAMFCapacity "RelativeAMFCapacity"
#define AMF_CONFIG_STRING_PLMNSupportList "PLMNSupportList"
#define AMF_CONFIG_STRING_SliceSupportList "SliceSupportList"
#define AMF_CONFIG_STRING_SST "SST"
#define AMF_CONFIG_STRING_SD "SD"
using namespace libconfig;
using namespace std;
namespace config{
typedef struct interface_cfg_s {
std::string if_name;
struct in_addr addr4;
struct in_addr network4;
struct in6_addr addr6;
unsigned int mtu;
unsigned int port;
util::thread_sched_params thread_rd_sched_params;
} interface_cfg_t;
typedef struct itti_cfg_s {
util::thread_sched_params itti_timer_sched_params;
util::thread_sched_params sx_sched_params;
util::thread_sched_params s5s8_sched_params;
util::thread_sched_params pgw_app_sched_params;
util::thread_sched_params async_cmd_sched_params;
} itti_cfg_t;
typedef struct guami_s{
string mcc;
string mnc;
string regionID;
string AmfSetID;
string AmfPointer;
}guami_t;
typedef struct slice_s{
string sST;
string sD;
}slice_t;
typedef struct plmn_support_item_s{
string mcc;
string mnc;
vector<slice_t> slice_list;
}plmn_item_t;
class amf_config{
public:
amf_config();
~amf_config();
int load(const std::string &config_file);
int load_interface(const Setting& if_cfg, interface_cfg_t & cfg);
int load_thread_sched_params(const libconfig::Setting& thread_sched_params_cfg, util::thread_sched_params& cfg);
void display();
public:
unsigned int instance;
string pid_dir;
interface_cfg_t n2;
itti_cfg_t itti;
unsigned int statistics_interval;
string AMF_Name;
vector<guami_t> guami_list;
unsigned int relativeAMFCapacity;
vector<plmn_item_t> plmn_list;
};
}
#endif
#include "amf_module_from_config.hpp"
#include "logger.hpp"
#include <iostream>
#include <string>
using namespace std;
namespace config{
int amf_modules::load(const std::string &config_file){
cout<<endl;
Logger::amf_app().debug("Load amf module configuration file(%s)",config_file.c_str());
Config cfg;
try{
cfg.readFile(config_file.c_str());
}catch(const FileIOException &fioex){
Logger::amf_app().error("I/O error while reading file %s - %s", config_file.c_str(), fioex.what());
throw;
}catch(const ParseException &pex){
Logger::amf_app().error("Parse error at %s:%d - %s", pex.getFile(), pex.getLine(), pex.getError());
throw;
}
const Setting &root = cfg.getRoot();
try{
const Setting& modules = root[MODULES_CONFIG_STRING_AMF_MODULES];
}catch(const SettingNotFoundException &nfex){
Logger::amf_app().error("%s : %s", nfex.what(), nfex.getPath());
return -1;
}
const Setting &modules = root[MODULES_CONFIG_STRING_AMF_MODULES];
const Setting &msg = modules[MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE];
int count = msg.getLength();
for(int i=0; i< count; i++){
const Setting & item = msg[i];
std::string typeOfMessage;
int procedure_code;
item.lookupValue(MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE_NAME, msgName);
item.lookupValue(MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE_PROCEDURECODE, procedure_code);
item.lookupValue(MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE_TYPEOFMSG, typeOfMessage);
procedureCode = (Ngap_ProcedureCode_t)procedure_code;
if(!(typeOfMessage.compare("initialMessage"))){
typeOfMsg = Ngap_NGAP_PDU_PR_initiatingMessage;
}else if(!(typeOfMessage.compare("successfuloutcome"))){
typeOfMsg = Ngap_NGAP_PDU_PR_successfulOutcome;
}else if(!(typeOfMessage.compare("unsuccessfuloutcome"))){
typeOfMsg = Ngap_NGAP_PDU_PR_unsuccessfulOutcome;
}else{
Logger::config().error("wrong NGAP message configuration");
}
}
}
void amf_modules::display(){
Logger::config().info( "======= AMF Registred Modules =======");
Logger::config().info( "NGAP Message Modules Repository(SourceCode) Path( ~/oai-5g-amf/src/ngap/ngapMsgs )");
Logger::config().info( "NGAP Message Modules:");
Logger::config().info( "- %s([%d,%d])\n", msgName.c_str(), procedureCode, typeOfMsg);
}
}
#ifndef _AMF_MODULE_FROM_CONFIG_H_
#define _AMF_MODULE_FROM_CONFIG_H_
#include <arpa/inet.h>
#include <libconfig.h++>
#include <netinet/in.h>
#include <sys/socket.h>
#include <mutex>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include "Ngap_ProcedureCode.h"
#include "Ngap_NGAP-PDU.h"
#define MODULES_CONFIG_STRING_AMF_MODULES "MODULES"
#define MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE "NGAP_MESSAGE"
#define MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE_NAME "MSG_NAME"
#define MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE_PROCEDURECODE "ProcedureCode"
#define MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE_TYPEOFMSG "TypeOfMessage"
using namespace libconfig;
namespace config{
class amf_modules{
public:
int load(const std::string &config_file);
void display();
void makeModulesAlive();
private:
std::string msgName;//vector to store more msgs
Ngap_NGAP_PDU_PR typeOfMsg;
Ngap_ProcedureCode_t procedureCode;
// NGSetupRequestMsg *ngSetupRequest;
};
}
#endif
#include "amf_n1.hpp"
#include "itti.hpp"
#include "logger.hpp"
using namespace amf;
extern itti_mw * itti_inst;
void amf_n1_task(void*);
void amf_n1_task(void*){
const task_id_t task_id = TASK_AMF_N1;
itti_inst->notify_task_ready(task_id);
do{
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
switch(msg->msg_type){
default:
Logger::task_amf_n1().error("no handler for msg type %d",msg->msg_type);
}
}while(true);
}
amf_n1::amf_n1(){
if(itti_inst->create_task(TASK_AMF_N1, amf_n1_task, nullptr) ) {
Logger::amf_n1().error( "Cannot create task TASK_AMF_N1" );
throw std::runtime_error( "Cannot create task TASK_AMF_N1" );
}
Logger::task_amf_n1().startup( "Started" );
Logger::task_amf_n1().debug("construct amf_n1 successfully");
}
amf_n1::~amf_n1(){}
#ifndef _AMF_N1_H_
#define _AMF_N1_H_
#include <map>
#include <shared_mutex>
#include "nas_context.hpp"
namespace amf{
class amf_n1{
public:
amf_n1();
~amf_n1();
//void handle_itti_message(itti_nas_signaling_establishment_req & nas_signaling_estb_req);
private:
std::map<long, std::shared_ptr<nas_context>> amfueid2nas_context; // amf ue ngap id
mutable std::shared_mutex m_amfueid2nas_context;
};
}
#endif
#include "amf_n2.hpp"
#include "logger.hpp"
#include "sctp_server.hpp"
#include "itti.hpp"
using namespace amf;
extern itti_mw * itti_inst;
extern amf_n2 * amf_n2_inst;
void amf_n2_task(void*);
void amf_n2_task(void *args_p){
const task_id_t task_id = TASK_AMF_N2;
itti_inst->notify_task_ready(task_id);
do{
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
switch(msg->msg_type){
case NEW_SCTP_ASSOCIATION:{
Logger::task_amf_n2().info("Received NEW_SCTP_ASSOCIATION");
itti_new_sctp_association *m = dynamic_cast<itti_new_sctp_association*>(msg);
amf_n2_inst->handle_itti_message(ref(*m));
}
break;
case NG_SETUP_REQ:{
Logger::task_amf_n2().info("Received NGSetupRequest message, handling");
itti_ng_setup_request *m = dynamic_cast<itti_ng_setup_request*>(msg);
amf_n2_inst->handle_itti_message(ref(*m));
}
break;
default:
Logger::task_amf_n2().info( "no handler for msg type %d", msg->msg_type);
}
}while(true);
}
amf_n2::amf_n2(const string &address, const uint16_t port_num) : ngap_app(address, port_num){
if (itti_inst->create_task(TASK_AMF_N2, amf_n2_task, nullptr) ) {
Logger::amf_n2().error( "Cannot create task TASK_AMF_N2" );
throw std::runtime_error( "Cannot create task TASK_AMF_N2" );
}
Logger::task_amf_n2().startup( "Started" );
Logger::task_amf_n2().debug("construct amf_n2 successfully");
}
amf_n2::~amf_n2(){}
/*
void amf_n2::handle_receive(bstring payload, sctp_assoc_id_t assoc_id, sctp_stream_id_t stream, sctp_stream_id_t instreams, sctp_stream_id_t outstreams){
Logger::amf_n2().debug("ngap handle sctp payload from sctp_server on assoc_id(%d), stream_id(%d), instreams(%d), outstreams(%d)", assoc_id,stream,instreams,outstreams);
Logger::amf_n2().debug("receiving buffer(%p)",bdata(payload));
printf("\nbuffer 0x");
for(int i=0; i< payload->slen; i++){
if(!payload->data[i])
printf("00");
else
printf("%x",payload->data[i]);
}
printf("\n\n");
int ret = sctp_s_38412.sctp_send_msg(assoc_id, stream, &payload);
Logger::amf_n2().debug("sctp_s_38412.sctp_send_msg test with sending result(%d): 0 is OK, else not OK", ret);
}
*/
/******************************************************** NGAP Messages Handlers******************************************************************/
void amf_n2::handle_itti_message(itti_new_sctp_association &new_assoc){
}
void amf_n2::handle_itti_message(itti_ng_setup_request &ngsetupreq){
Logger::amf_n2().debug("parameters(assoc_id(%d))(stream(%d))",ngsetupreq.assoc_id, ngsetupreq.stream);
//association GlobalRANNodeID with assoc_id
//store RAN Node Name in gNB context, if present
//verify PLMN Identity and TAC with configuration and store supportedTAList in gNB context, if verified; else response NG SETUP FAILURE with cause "Unknown PLMN"(9.3.1.2, ts38413)
//store Paging DRX in gNB context
//encode NG SETUP RESPONSE message with information stored in configuration file and send_msg
}
//void amf_n2::handle_itti_message(itti_initial_ue_message &init_ue_msg){
//create ngap-ue context and store in gNB context to store UE information in gNB, for example, here RAN UE NGAP ID and location information and RRC Establishment Cause
//send NAS-PDU to NAS layer
//}
#ifndef _AMF_N2_H_
#define _AMF_N2_H_
#include "ngap_app.hpp"
#include "itti_msg_n2.hpp"
#include "ue_ngap_context.hpp"
namespace amf{
class amf_n2 : public ngap::ngap_app{
public:
amf_n2(const string &address, const uint16_t port_num);
~amf_n2();
//void handle_receive(bstring payload, sctp_assoc_id_t assoc_id, sctp_stream_id_t stream, sctp_stream_id_t instreams, sctp_stream_id_t outstreams);
void handle_itti_message(itti_new_sctp_association &new_assoc);
void handle_itti_message(itti_ng_setup_request &ngsetupreq);
//void handle_itti_message(itti_initial_ue_message &init_ue_msg);
private:
std::map<uint32_t, std::shared_ptr<ue_ngap_context>> ranid2uecontext;// ran ue ngap id
mutable std::shared_mutex m_ranid2uecontext;
};
}
#endif
#include "amf_statistics.hpp"
#include "logger.hpp"
#include <iostream>
using namespace std;
void statistics::display(){
cout<<endl;
Logger::amf_app().info("--------------------------------------------------");
Logger::amf_app().info("| connected gNBs | connected UEs | registred UEs |");
Logger::amf_app().info("--------------------------------------------------");
Logger::amf_app().info("| %d | %d | %d |",gNB_connected,UE_connected,UE_registred);
Logger::amf_app().info("--------------------------------------------------");
}
statistics::statistics(){
gNB_connected = 0;
UE_connected = 0;
UE_registred = 0;
}
statistics::~statistics(){}
#ifndef _STATISTICS_H_
#define _STATISTICS_H_
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
class statistics{
public:
void display();
statistics();
~statistics();
private:
uint32_t gNB_connected;
uint32_t UE_connected;
uint32_t UE_registred;
//uint32_t system_pdu_sessions;
};
#endif
include_directories(${SRC_TOP_DIR}/common)
include_directories(${SRC_TOP_DIR}/../build/ext/spdlog/include)
add_library( LOG STATIC
${SRC_TOP_DIR}/common/logger.cpp
)
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file common_defs.h
\brief
\author Sebastien ROUX, Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_COMMON_DEFS_SEEN
#define FILE_COMMON_DEFS_SEEN
#include <arpa/inet.h>
#include <stdint.h>
#define RETURNclear (int)2
#define RETURNerror (int)1
#define RETURNok (int)0
typedef enum {
/* Fatal errors - received message should not be processed */
TLV_MAC_MISMATCH = -14,
TLV_BUFFER_NULL = -13,
TLV_BUFFER_TOO_SHORT = -12,
TLV_PROTOCOL_NOT_SUPPORTED = -11,
TLV_WRONG_MESSAGE_TYPE = -10,
TLV_OCTET_STRING_TOO_LONG_FOR_IEI = -9,
TLV_VALUE_DOESNT_MATCH = -4,
TLV_MANDATORY_FIELD_NOT_PRESENT = -3,
TLV_UNEXPECTED_IEI = -2,
// RETURNerror = -1,
// RETURNok = 0,
TLV_ERROR_OK = RETURNok,
/* Defines error code limit below which received message should be discarded
* because it cannot be further processed */
TLV_FATAL_ERROR = TLV_VALUE_DOESNT_MATCH
} error_code_e;
//------------------------------------------------------------------------------
#define DECODE_U8(bUFFER, vALUE, sIZE) \
vALUE = *(uint8_t*)(bUFFER); \
sIZE += sizeof(uint8_t)
#define DECODE_U16(bUFFER, vALUE, sIZE) \
vALUE = ntohs(*(uint16_t*)(bUFFER)); \
sIZE += sizeof(uint16_t)
#define DECODE_U24(bUFFER, vALUE, sIZE) \
vALUE = ntohl(*(uint32_t*)(bUFFER)) >> 8; \
sIZE += sizeof(uint8_t) + sizeof(uint16_t)
#define DECODE_U32(bUFFER, vALUE, sIZE) \
vALUE = ntohl(*(uint32_t*)(bUFFER)); \
sIZE += sizeof(uint32_t)
#if (BYTE_ORDER == LITTLE_ENDIAN)
# define DECODE_LENGTH_U16(bUFFER, vALUE, sIZE) \
vALUE = ((*(bUFFER)) << 8) | (*((bUFFER) + 1)); \
sIZE += sizeof(uint16_t)
#else
# define DECODE_LENGTH_U16(bUFFER, vALUE, sIZE) \
vALUE = (*(bUFFER)) | (*((bUFFER) + 1) << 8); \
sIZE += sizeof(uint16_t)
#endif
#define ENCODE_U8(buffer, value, size) \
*(uint8_t*)(buffer) = value; \
size += sizeof(uint8_t)
#define ENCODE_U16(buffer, value, size) \
*(uint16_t*)(buffer) = htons(value); \
size += sizeof(uint16_t)
#define ENCODE_U24(buffer, value, size) \
*(uint32_t*)(buffer) = htonl(value); \
size += sizeof(uint8_t) + sizeof(uint16_t)
#define ENCODE_U32(buffer, value, size) \
*(uint32_t*)(buffer) = htonl(value); \
size += sizeof(uint32_t)
#define IPV4_STR_ADDR_TO_INT_NWBO(AdDr_StR,NwBo,MeSsAgE ) do {\
struct in_addr inp;\
if ( inet_aton(AdDr_StR, &inp ) < 0 ) {\
AssertFatal (0, MeSsAgE);\
} else {\
NwBo = inp.s_addr;\
}\
} while (0)
#define NIPADDR(addr) \
(uint8_t)(addr & 0x000000FF), \
(uint8_t)((addr & 0x0000FF00) >> 8), \
(uint8_t)((addr & 0x00FF0000) >> 16), \
(uint8_t)((addr & 0xFF000000) >> 24)
#define HIPADDR(addr) \
(uint8_t)((addr & 0xFF000000) >> 24),\
(uint8_t)((addr & 0x00FF0000) >> 16),\
(uint8_t)((addr & 0x0000FF00) >> 8), \
(uint8_t)(addr & 0x000000FF)
#define NIP6ADDR(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
#define IN6_ARE_ADDR_MASKED_EQUAL(a,b,m) \
(((((__const uint32_t *) (a))[0] & (((__const uint32_t *) (m))[0])) == (((__const uint32_t *) (b))[0] & (((__const uint32_t *) (m))[0]))) \
&& ((((__const uint32_t *) (a))[1] & (((__const uint32_t *) (m))[1])) == (((__const uint32_t *) (b))[1] & (((__const uint32_t *) (m))[1]))) \
&& ((((__const uint32_t *) (a))[2] & (((__const uint32_t *) (m))[2])) == (((__const uint32_t *) (b))[2] & (((__const uint32_t *) (m))[2]))) \
&& ((((__const uint32_t *) (a))[3] & (((__const uint32_t *) (m))[3])) == (((__const uint32_t *) (b))[3] & (((__const uint32_t *) (m))[3]))))
////////////
#define IPV4_STR_ADDR_TO_INADDR(AdDr_StR,InAdDr,MeSsAgE ) do {\
if ( inet_aton(AdDr_StR, &InAdDr ) <= 0 ) {\
throw (MeSsAgE);\
}\
} while (0)
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#endif /* FILE_COMMON_DEFS_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file conversions.cpp
\brief
\author Sebastien ROUX
\company Eurecom
*/
#include "conversions.hpp"
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
#include <inttypes.h>
#include <arpa/inet.h>
static const char hex_to_ascii_table[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
};
static const signed char ascii_to_hex_table[0x100] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
void conv::hexa_to_ascii (
uint8_t * from,
char *to,
size_t length)
{
size_t i;
for (i = 0; i < length; i++) {
uint8_t upper = (from[i] & 0xf0) >> 4;
uint8_t lower = from[i] & 0x0f;
to[2 * i] = hex_to_ascii_table[upper];
to[2 * i + 1] = hex_to_ascii_table[lower];
}
}
int conv::ascii_to_hex (
uint8_t * dst,
const char *h)
{
const unsigned char *hex = (const unsigned char *)h;
unsigned i = 0;
for (;;) {
int high,
low;
while (*hex && isspace (*hex))
hex++;
if (!*hex)
return 1;
high = ascii_to_hex_table[*hex++];
if (high < 0)
return 0;
while (*hex && isspace (*hex))
hex++;
if (!*hex)
return 0;
low = ascii_to_hex_table[*hex++];
if (low < 0)
return 0;
dst[i++] = (high << 4) | low;
}
}
//------------------------------------------------------------------------------
std::string conv::mccToString(const uint8_t digit1, const uint8_t digit2, const uint8_t digit3)
{
std::string s = {};
uint16_t mcc16 = digit1*100+digit2*10+digit3;
//s.append(std::to_string(digit1)).append(std::to_string(digit2)).append(std::to_string(digit3));
s.append(std::to_string(mcc16));
return s;
}
//------------------------------------------------------------------------------
std::string conv::mncToString(const uint8_t digit1, const uint8_t digit2, const uint8_t digit3)
{
std::string s = {};
uint16_t mcc16 = 0;
if (digit3 == 0x0F) {
mcc16 = digit1*10+digit2;
} else {
mcc16 = digit1*100+digit2*10+digit3;
}
s.append(std::to_string(mcc16));
return s;
}
//------------------------------------------------------------------------------
struct in_addr conv::fromString(const std::string addr4)
{
unsigned char buf[sizeof(struct in6_addr)] = {};
int s = inet_pton(AF_INET, addr4.c_str(), buf);
struct in_addr * ia = (struct in_addr *)buf;
return *ia;
}
//------------------------------------------------------------------------------
std::string conv::toString(const struct in_addr& inaddr)
{
std::string s = {};
char str[INET6_ADDRSTRLEN] = {};
if (inet_ntop(AF_INET, (const void *)&inaddr, str, INET6_ADDRSTRLEN) == NULL) {
s.append("Error in_addr");
} else {
s.append(str);
}
return s;
}
//------------------------------------------------------------------------------
std::string conv::toString(const struct in6_addr& in6addr)
{
std::string s = {};
char str[INET6_ADDRSTRLEN] = {};
if (inet_ntop(AF_INET6, (const void *)&in6addr, str, INET6_ADDRSTRLEN) == nullptr) {
s.append("Error in6_addr");
} else {
s.append(str);
}
return s;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file conversions.hpp
\brief
\author Sebastien ROUX, Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_CONVERSIONS_HPP_SEEN
#define FILE_CONVERSIONS_HPP_SEEN
#include <stdint.h>
#include <string>
#include <netinet/in.h>
/* Used to format an uint32_t containing an ipv4 address */
#define IN_ADDR_FMT "%u.%u.%u.%u"
#define PRI_IN_ADDR(aDDRESS) \
(uint8_t)((aDDRESS.s_addr) & 0x000000ff), \
(uint8_t)(((aDDRESS.s_addr) & 0x0000ff00) >> 8 ), \
(uint8_t)(((aDDRESS.s_addr) & 0x00ff0000) >> 16), \
(uint8_t)(((aDDRESS.s_addr) & 0xff000000) >> 24)
#define IPV4_ADDR_DISPLAY_8(aDDRESS) \
(aDDRESS)[0], (aDDRESS)[1], (aDDRESS)[2], (aDDRESS)[3]
class conv {
public:
static void hexa_to_ascii(uint8_t *from, char *to, size_t length);
static int ascii_to_hex(uint8_t *dst, const char *h);
static struct in_addr fromString(const std::string addr4);
static std::string toString(const struct in_addr& inaddr);
static std::string toString(const struct in6_addr& in6addr);
static std::string mccToString(const uint8_t digit1, const uint8_t digit2, const uint8_t digit3);
static std::string mncToString(const uint8_t digit1, const uint8_t digit2, const uint8_t digit3);
};
#endif /* FILE_CONVERSIONS_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file endpoint.hpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_ENDPOINT_HPP_SEEN
#define FILE_ENDPOINT_HPP_SEEN
#include "conversions.hpp"
#include <arpa/inet.h>
#include <inttypes.h>
#include <sys/socket.h>
#include <string.h>
class endpoint {
public :
struct sockaddr_storage addr_storage;
socklen_t addr_storage_len;
endpoint() : addr_storage(), addr_storage_len(sizeof(struct sockaddr_storage)) {};
endpoint(const endpoint& e) : addr_storage(e.addr_storage), addr_storage_len(e.addr_storage_len) {};
endpoint(const struct sockaddr_storage& addr, const socklen_t len) : addr_storage(addr), addr_storage_len(len) {};
endpoint(const struct in_addr& addr, const uint16_t port)
{
struct sockaddr_in * addr_in = (struct sockaddr_in *)&addr_storage;
addr_in->sin_family = AF_INET;
addr_in->sin_port = htons(port);
addr_in->sin_addr.s_addr = addr.s_addr;
addr_storage_len = sizeof(struct sockaddr_in);
};
endpoint(const struct in6_addr& addr6, const uint16_t port)
{
struct sockaddr_in6 * addr_in6 = (struct sockaddr_in6 *)&addr_storage;
addr_in6->sin6_family = AF_INET6;
addr_in6->sin6_port = htons(port);
addr_in6->sin6_flowinfo = 0;
memcpy(&addr_in6->sin6_addr, &addr6, sizeof(struct in6_addr));
addr_in6->sin6_scope_id = 0;
addr_storage_len = sizeof(struct sockaddr_in6);
};
uint16_t port() const
{
return ntohs(((struct sockaddr_in *)&addr_storage)->sin_port);
}
sa_family_t family() const
{
return addr_storage.ss_family;
}
std::string toString() const
{
std::string str;
if (addr_storage.ss_family == AF_INET) {
struct sockaddr_in * addr_in = (struct sockaddr_in *)&addr_storage;
str.append(conv::toString(addr_in->sin_addr));
str.append(":").append(std::to_string(ntohs(addr_in->sin_port)));
}
else if (addr_storage.ss_family == AF_INET6) {
struct sockaddr_in6 * addr_in6 = (struct sockaddr_in6 *)&addr_storage;
str.append(conv::toString(addr_in6->sin6_addr));
str.append(":").append(std::to_string(ntohs(addr_in6->sin6_port)));
}
return str;
}
};
#endif
#include "logger.hpp"
#include "spdlog/sinks/syslog_sink.h"
#include <iostream>
#include <sstream>
#include <string>
#include <memory>
Logger *Logger::m_singleton = NULL;
void Logger::_init(const char *app, const bool log_stdout, const bool log_rot_file){
int num_sinks = 0;
spdlog::set_async_mode(2048);
#if TRACE_IS_ON
spdlog::level::level_enum llevel = spdlog::level::trace;
#elif DEBUG_IS_ON
spdlog::level::level_enum llevel = spdlog::level::debug;
#elif INFO_IS_ON
spdlog::level::level_enum llevel = spdlog::level::info;
#else
spdlog::level::level_enum llevel = spdlog::level::warn;
#endif
if(log_stdout){
std::string filename = fmt::format("./{}.log",app);
m_sinks.push_back(std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>());
m_sinks[num_sinks++].get()->set_level(llevel);
}
if(log_rot_file){
std::string filename = fmt::format("./{}.log",app);
m_sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(filename, 5*1024*1024, 3));
}
std::stringstream ss;
ss << "[%Y-%m-%dT%H:%M:%S.%f] [" << app << "] [%n] [%l] %v";
m_async_cmd = new _Logger("asnyc_c", m_sinks, ss.str().c_str());
m_amf_app = new _Logger("amf_app", m_sinks, ss.str().c_str());
m_config = new _Logger("configurations", m_sinks, ss.str().c_str());
m_system = new _Logger("system", m_sinks, ss.str().c_str());
m_sctp = new _Logger("sctp", m_sinks, ss.str().c_str());
m_nas_mm = new _Logger("nas_mm", m_sinks, ss.str().c_str());
m_ngap = new _Logger("ngap", m_sinks, ss.str().c_str());
m_itti = new _Logger("itti", m_sinks, ss.str().c_str());
m_amf_n2 = new _Logger("amf_n2", m_sinks, ss.str().c_str());
m_task_amf_n2 = new _Logger("TASK_AMF_N2", m_sinks, ss.str().c_str());
m_amf_n1 = new _Logger("amf_n1", m_sinks, ss.str().c_str());
m_task_amf_n1 = new _Logger("TASK_AMF_N1", m_sinks, ss.str().c_str());
}
_Logger::_Logger( const char *category, std::vector<spdlog::sink_ptr> &sinks, const char *pattern )
: m_log( category, sinks.begin(), sinks.end() )
{
m_log.set_pattern( pattern );
#if TRACE_IS_ON
m_log.set_level( spdlog::level::trace );
#elif DEBUG_IS_ON
m_log.set_level( spdlog::level::debug );
#elif INFO_IS_ON
m_log.set_level( spdlog::level::info );
#else
m_log.set_level( spdlog::level::warn );
#endif
}
void _Logger::trace( const char *format, ... )
{
#if TRACE_IS_ON
va_list args;
va_start( args, format );
log( _ltTrace, format, args );
va_end( args );
#endif
}
void _Logger::trace( const std::string &format, ... )
{
#if TRACE_IS_ON
va_list args;
va_start( args, format );
log( _ltTrace, format.c_str(), args );
va_end( args );
#endif
}
void _Logger::debug( const char *format, ... )
{
#if DEBUG_IS_ON
va_list args;
va_start( args, format );
log( _ltDebug, format, args );
va_end( args );
#endif
}
void _Logger::debug( const std::string &format, ... )
{
#if DEBUG_IS_ON
va_list args;
va_start( args, format );
log( _ltDebug, format.c_str(), args );
va_end( args );
#endif
}
void _Logger::info( const char *format, ... )
{
#if INFO_IS_ON
va_list args;
va_start( args, format );
log( _ltInfo, format, args );
va_end( args );
#endif
}
void _Logger::info( const std::string &format, ... )
{
#if INFO_IS_ON
va_list args;
va_start( args, format );
log( _ltInfo, format.c_str(), args );
va_end( args );
#endif
}
void _Logger::startup( const char *format, ... )
{
va_list args;
va_start( args, format );
log( _ltStartup, format, args );
va_end( args );
}
void _Logger::startup( const std::string &format, ... )
{
va_list args;
va_start( args, format );
log( _ltStartup, format.c_str(), args );
va_end( args );
}
void _Logger::warn( const char *format, ... )
{
va_list args;
va_start( args, format );
log( _ltWarn, format, args );
va_end( args );
}
void _Logger::warn( const std::string &format, ... )
{
va_list args;
va_start( args, format );
log( _ltWarn, format.c_str(), args );
va_end( args );
}
void _Logger::error( const char *format, ... )
{
va_list args;
va_start( args, format );
log( _ltError, format, args );
va_end( args );
}
void _Logger::error( const std::string &format, ... )
{
va_list args;
va_start( args, format );
log( _ltError, format.c_str(), args );
va_end( args );
}
void _Logger::log( _LogType lt, const char *format, va_list &args )
{
char buffer[ 2048 ];
vsnprintf( buffer, sizeof(buffer), format, args );
switch ( lt )
{
case _ltTrace: m_log.trace( buffer ); break;
case _ltDebug: m_log.debug( buffer ); break;
case _ltInfo: m_log.info( buffer ); break;
case _ltStartup: m_log.warn( buffer ); break;
case _ltWarn: m_log.error( buffer ); break;
case _ltError: m_log.critical( buffer ); break;
}
}
#ifndef __LOGGER_H
#define __LOGGER_H
#include <cstdarg>
#include <stdexcept>
#include <vector>
#define SPDLOG_LEVEL_NAMES { "trace", "debug", "info ", "start", "warn ", "error", "off " };
#define SPDLOG_ENABLE_SYSLOG
#include "spdlog/spdlog.h"
class LoggerException : public std::runtime_error
{
public:
explicit LoggerException(const char *m) : std::runtime_error(m) {}
explicit LoggerException(const std::string &m) : std::runtime_error(m) {}
};
class _Logger
{
public:
_Logger(const char * category, std::vector<spdlog::sink_ptr> &sinks, const char *pattern);
void trace(const char *format, ...);
void trace(const std::string &format, ...);
void debug(const char *format, ...);
void debug(const std::string &format, ...);
void info(const char *format, ...);
void info(const std::string &format, ...);
void startup(const char *format, ...);
void startup(const std::string &format, ...);
void warn(const char *format, ...);
void warn(const std::string &format, ...);
void error(const char *format, ...);
void error(const std::string &format, ...);
private:
_Logger();
enum _LogType
{
_ltTrace,
_ltDebug,
_ltInfo,
_ltStartup,
_ltWarn,
_ltError
};
void log(_LogType lt, const char *format, va_list &args);
spdlog::logger m_log;
};
class Logger
{
public:
static void init(const char *app, const bool log_stdout, const bool log_rot_file){singleton()._init(app, log_stdout, log_rot_file);}
static void init(const std::string &app, const bool log_stdout, const bool log_rot_file){init(app.c_str(), log_stdout, log_rot_file);}
static _Logger &async_cmd(){return *singleton().m_async_cmd;}
static _Logger &amf_app(){return *singleton().m_amf_app;}
static _Logger &config(){return *singleton().m_config;}
static _Logger &system(){return *singleton().m_system;}
static _Logger &sctp(){return *singleton().m_sctp;}
static _Logger &nas_mm(){return *singleton().m_nas_mm;}
static _Logger &ngap(){return *singleton().m_ngap;}
static _Logger &itti(){return *singleton().m_itti;}
static _Logger &amf_n2(){return *singleton().m_amf_n2;}
static _Logger &task_amf_n2(){return *singleton().m_task_amf_n2;}
static _Logger &amf_n1(){return *singleton().m_amf_n1;}
static _Logger &task_amf_n1(){return *singleton().m_task_amf_n1;}
private:
static Logger *m_singleton;
static Logger &singleton(){if(!m_singleton) m_singleton = new Logger(); return *m_singleton;}
Logger(){}
~Logger(){}
void _init(const char *app, const bool log_stdout, const bool log_rot_file);
std::vector<spdlog::sink_ptr> m_sinks;
std::string m_pattern;
_Logger *m_async_cmd;
_Logger *m_amf_app;
_Logger *m_config;
_Logger *m_system;
_Logger *m_sctp;
_Logger *m_nas_mm;
_Logger *m_ngap;
_Logger *m_itti;
_Logger *m_amf_n2;
_Logger *m_task_amf_n2;
_Logger *m_amf_n1;
_Logger *m_task_amf_n1;
};
#endif
cmake_minimum_required (VERSION 3.0.2)
project(OpenAirInterface)
macro(add_list_string_option name val helpstr)
if(DEFINED ${name})
set(value ${${name}})
else(DEFINED ${name})
set(value ${val})
endif()
set(${name} ${value} CACHE STRING "${helpstr}")
set_property(CACHE ${name} PROPERTY STRINGS ${ARGN})
if(NOT "${value}" STREQUAL "False")
add_definitions("-D${name}=\"${value}\"")
endif()
endmacro(add_list_string_option)
SET(STATIC_LINKING FALSE CACHE BOOL "Build a static binary?")
IF(STATIC_LINKING)
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
ENDIF(STATIC_LINKING)
add_list_string_option(CMAKE_BUILD_TYPE "RelWithDebInfo" "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." Debug Release
RelWithDebInfo MinSizeRel)
Message("Build type is ${CMAKE_BUILD_TYPE}")
if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
add_boolean_option(LOG_OAI True "Thread safe logging API")
add_boolean_option(LOG_OAI_MINIMAL True "Thread safe logging API, log only levels above NOTICE")
SET(ASAN asan)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_boolean_option(LOG_OAI True "Thread safe logging API")
SET(ASAN asan)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE "MinSizeRel")
endif()
Message("Build type is ${CMAKE_BUILD_TYPE}")
Message("Architecture is ${CMAKE_SYSTEM_PROCESSOR}")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
set(C_FLAGS_PROCESSOR "-gdwarf-2 -mfloat-abi=hard -mfpu=neon -lgcc -lrt")
else (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
set(C_FLAGS_PROCESSOR "-msse4.2")
endif()
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} ${C_FLAGS_PROCESSOR} -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC ")
# add autoTOOLS definitions that were maybe used!
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP")
add_definitions(-DCMAKER)
add_definitions(-DBSTRLIB_CAN_USE_STL=1 -DBSTRLIB_CAN_USE_IOSTREAM=1 -DBSTRLIB_THROWS_EXCEPTIONS=1)
if(STATIC_LINKING)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fno-omit-frame-pointer")
else (STATIC_LINKING)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fsanitize=address -fno-omit-frame-pointer")
endif(STATIC_LINKING)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O2 -fno-omit-frame-pointer -s -DINFO_IS_ON=1 ")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -O2 -DINFO_IS_ON=1 ")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS} -Os -s -DTRACE_IS_ON=1 -DDEBUG_IS_ON=1 -DINFO_IS_ON=1")
if(STATIC_LINKING)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -std=c++17 -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fno-omit-frame-pointer -DBUPT=1 -DEURECOM=0")
else(STATIC_LINKING)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -std=c++17 -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fsanitize=address -fno-omit-frame-pointer -DBUPT=1 -DEURECOM=0")
endif(STATIC_LINKING)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -std=c++17 -O2 -fno-omit-frame-pointer -s -DINFO_IS_ON=1 -DBUPT=1 -DEURECOM=0")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -std=c++17 -g -O2 -DINFO_IS_ON=1 -DBUPT=1 -DEURECOM=0")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -std=c++17 -Os -s -DTRACE_IS_ON=1 -DDEBUG_IS_ON=1 -DINFO_IS_ON=1")
set(CMAKE_MODULE_PATH "${OPENAIRCN_DIR}/build/cmake_modules" "${CMAKE_MODULE_PATH}")
include(FindPkgConfig)
message("${OPENAIRCN_DIR}/build/cmake_modules")
include_directories(${SRC_TOP_DIR}/oai-amf)
include_directories(${SRC_TOP_DIR}/amf-app)
include_directories(${SRC_TOP_DIR}/../build/ext/spdlog/include)
### for common
include_directories(${SRC_TOP_DIR}/common)
file(GLOB COMMON_SRC ${SRC_TOP_DIR}/common/conversions.cpp)
### end for common
### for utils/bstr
include_directories(${SRC_TOP_DIR}/utils/bstr)
include_directories(${SRC_TOP_DIR}/utils)
file(GLOB BSTR_SRC
${SRC_TOP_DIR}/utils/bstr/bstrlib.c
${SRC_TOP_DIR}/utils/thread_sched.cpp
)
##end for utils/bstr
### for sctp
include_directories(${SRC_TOP_DIR}/sctp)
file(GLOB SCTP_SRC ${SRC_TOP_DIR}/sctp/sctp_server.cpp)
#end for sctp
### for ngap
include_directories(${SRC_TOP_DIR}/ngap/ngap_app)
file(GLOB NGAP_SRC ${SRC_TOP_DIR}/ngap/ngap_app/ngap_app.cpp)
###end for ngap
### for itti
include_directories(${SRC_TOP_DIR}/itti)
file(GLOB ITTI_SRC
${SRC_TOP_DIR}/itti/itti.cpp
${SRC_TOP_DIR}/itti/itti_msg.cpp
)
###end for itti
### for log
add_library( LOG STATIC
${SRC_TOP_DIR}/common/logger.cpp)
add_library( OPTIONS STATIC
${SRC_TOP_DIR}/oai-amf/options.cpp)
###end for log
### for config
add_library( CONFIGS STATIC
${SRC_TOP_DIR}/amf-app/amf_config.cpp)
pkg_search_module(CONFIG REQUIRED libconfig++)
include_directories(${CONFIG_INCLUDE_DIRS})
### end for config
add_executable(amf
#${SRC_TOP_DIR}/oai-amf/main.cpp
#${SRC_TOP_DIR}/ngap/main.cpp
${SRC_TOP_DIR}/itti/main.cpp
${COMMON_SRC} ${BSTR_SRC} ${SCTP_SRC} ${NGAP_SRC} ${ITTI_SRC}
)
# LOG from oai-amf/CMakeLists.txt
target_link_libraries(amf -Wl,--start-group LOG OPTIONS CONFIGS config++ sctp pthread)
This diff is collapsed.
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file itti.hpp
\brief
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#ifndef SRC_OAI_ITTI_ITTI_HPP_INCLUDED_
#define SRC_OAI_ITTI_ITTI_HPP_INCLUDED_
#include <chrono>
#include <condition_variable>
//#include <iomanip>
#include <iostream>
#include <memory>
#include <mutex>
#include <queue>
#include <set>
#include <stdint.h>
#include <thread>
#include "itti_msg.hpp"
#include "thread_sched.hpp"
typedef volatile enum task_state_s {
TASK_STATE_NOT_CONFIGURED, TASK_STATE_STARTING, TASK_STATE_READY, TASK_STATE_ENDED, TASK_STATE_MAX,
} task_state_t;
typedef uint32_t timer_id_t;
#define ITTI_INVALID_TIMER_ID (timer_id_t)0
class itti_timer {
public:
itti_timer(const timer_id_t id, const task_id_t task_id, const uint32_t interval_sec, const uint32_t interval_us, uint64_t arg1_user, uint64_t arg2_user) :
id(id), task_id(task_id), arg1_user(arg1_user), arg2_user(arg2_user) {
time_out = std::chrono::system_clock::now() + std::chrono::seconds(interval_sec) + std::chrono::microseconds(interval_us);
}
itti_timer(const timer_id_t id, const task_id_t task_id, const std::chrono::system_clock::time_point time_out, uint64_t arg1_user, uint64_t arg2_user) :
id(id), task_id(task_id), time_out(time_out), arg1_user(arg1_user), arg2_user(arg2_user) {
}
itti_timer(const itti_timer &t) : id(t.id), task_id(t.task_id) , time_out(t.time_out), arg1_user(t.arg1_user), arg2_user(t.arg2_user) {}
//itti_timer(itti_timer&& t) noexcept : id(std::move(t.id)), task_id(std::move(t.task_id)) , time_out(std::move(t.time_out)) {}
bool operator<(const itti_timer& t) const { return time_out < t.time_out; }
~itti_timer() {}
timer_id_t id;
task_id_t task_id;
std::chrono::system_clock::time_point time_out;
uint64_t arg1_user;
uint64_t arg2_user;
};
//------------------------------------------------------------------------------
struct timer_comparator {
bool operator()(const itti_timer &left, const itti_timer &right) const
{
return (left.time_out < right.time_out);
}
};
class itti_task_ctxt {
public:
explicit itti_task_ctxt(const task_id_t task_id) :
task_id(task_id), m_state(), task_state(TASK_STATE_STARTING), msg_queue() , m_queue(), c_queue() {}
~itti_task_ctxt() {}
const task_id_t task_id;
/*
* pthread associated with the thread
*/
//std::thread::id thread_id;
std::thread thread;
/*
* State of the thread
*/
std::mutex m_state;
volatile task_state_t task_state;
std::queue<std::shared_ptr<itti_msg>> msg_queue;
std::mutex m_queue;
std::condition_variable c_queue;
};
class itti_mw {
private:
itti_task_ctxt *itti_task_ctxts[TASK_MAX];
/*
* Current message number. Incremented every call to send_msg_to_task
*/
unsigned long msg_number;
timer_id_t timer_id;
std::mutex m_timer_id;
std::thread timer_thread;
std::atomic<int> created_tasks;
std::atomic<int> ready_tasks;
std::set<itti_timer, timer_comparator> timers;
itti_timer current_timer;
std::mutex m_timers;
std::condition_variable c_timers;
std::mutex m_timeout;
std::condition_variable c_timeout;
bool terminate;
static void timer_manager_task(const util::thread_sched_params& sched_params);
public:
itti_mw();
itti_mw(itti_mw const&) = delete;
void operator=(itti_mw const&) = delete;
~itti_mw();
void start(const util::thread_sched_params& sched_params);
timer_id_t increment_timer_id ();
unsigned int increment_message_number ();
/** \brief Send a broadcast message to every task
\param message_p Pointer to the message to send
@returns < 0 on failure, 0 otherwise
**/
int send_broadcast_msg(std::shared_ptr<itti_msg> message);
/** \brief Send a message to a task (could be itself)
\param message message to send
@returns -1 on failure, 0 otherwise
**/
int send_msg(std::shared_ptr<itti_msg> message);
/** \brief Retrieves a message in the queue associated to task_id.
* If the queue is empty, the thread is blocked till a new message arrives.
\param task_id Task ID of the receiving task
\param received_msg Pointer to the allocated message
**/
std::shared_ptr<itti_msg> receive_msg (task_id_t task_id);
/** \brief Try to retrieves a message in the queue associated to task_id.
\param task_id Task ID of the receiving task
\param received_msg Pointer to the allocated message
**/
std::shared_ptr<itti_msg> poll_msg(task_id_t task_id);
/** \brief Start thread associated to the task
* \param task_id task to start
* \param start_routine entry point for the task
* \param args_p Optional argument to pass to the start routine
* @returns -1 on failure, 0 otherwise
**/
int create_task (const task_id_t task_id,
void (*start_routine) (void *),
void *args_p);
/** \brief Notify ITTI of a started thread
* \param task_id of started task
* \param start_routine entry point for the task
* \param args_p Optional argument to pass to the start routine
* @returns -1 on failure, 0 otherwise
**/
int notify_task_ready(const task_id_t task_id);
/** \brief Indicates to ITTI if newly created tasks should wait for all tasks to be ready
* \param wait_tasks non 0 to make new created tasks to wait, 0 to let created tasks to run
**/
//void wait_ready(int wait_tasks);
/** \brief Mark the task as in ready state
* \param task_id task to mark as ready
**/
//void mark_task_ready(task_id_t task_id);
/** \brief handle signals and wait for all threads to join when the process complete.
* This function should be called from the main thread after having created all ITTI tasks.
**/
void wait_tasks_end(void);
/** \brief Send a termination message to all tasks.
* \param src_task_id task that is broadcasting the message.
**/
int send_terminate_msg(task_id_t src_task_id);
/** \brief Request a new timer
* \param interval_sec timer interval in seconds
* \param interval_us timer interval in micro seconds
* \param task_id task id of the task requesting the timer
* @returns 0 on failure, timer id otherwise
**/
timer_id_t timer_setup(
uint32_t interval_sec,
uint32_t interval_us,
task_id_t task_id,
uint64_t arg1_user = 0,
uint64_t arg2_user = 0);
/** \brief Remove the timer from list
* \param timer_id unique timer id
* \param task_id task id of the task that requested the timer
* @returns -1 on failure, 0 otherwise
**/
int timer_remove (timer_id_t timer_id);
static void signal_handler( int signum );
};
#endif /* SRC_OAI_ITTI_ITTI_HPP_INCLUDED_ */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file itti_msg.cpp
\brief
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#include "itti_msg.hpp"
#include "itti.hpp"
extern itti_mw *itti_inst;
itti_msg::itti_msg() :
msg_type(ITTI_MSG_TYPE_NONE), origin(TASK_NONE), destination(TASK_NONE) {
msg_num = itti_inst->increment_message_number();
};
itti_msg::itti_msg(const itti_msg_type_t msg_type, task_id_t origin, task_id_t destination) :
msg_type(msg_type), origin(origin), destination(destination) {
msg_num = itti_inst->increment_message_number();
};
itti_msg::itti_msg(const itti_msg& i) :
msg_type(i.msg_type),msg_num(i.msg_num), origin(i.origin), destination(i.destination) {
};
const char* itti_msg::get_msg_name()
{
return "UNINITIALIZED";
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file itti_msg.hpp
\brief
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#ifndef SRC_ITTI_ITTI_MSG_HPP_INCLUDED_
#define SRC_ITTI_ITTI_MSG_HPP_INCLUDED_
#include <stdint.h>
#include <utility>
typedef enum {
TASK_FIRST = 0,
TASK_ITTI_TIMER = TASK_FIRST,
TASK_ASYNC_SHELL_CMD,
TASK_NGAP,
TASK_AMF_N2,
TASK_AMF_N1,
TASK_AMF_APP,
TASK_MAX,
TASK_NONE,
TASK_ALL = 255
} task_id_t;
typedef enum message_priorities_e {
MESSAGE_PRIORITY_MAX = 100,
MESSAGE_PRIORITY_MAX_LEAST = 85,
MESSAGE_PRIORITY_MED_PLUS = 70,
MESSAGE_PRIORITY_MED = 55,
MESSAGE_PRIORITY_MED_LEAST = 40,
MESSAGE_PRIORITY_MIN_PLUS = 25,
MESSAGE_PRIORITY_MIN = 10,
} message_priorities_t;
typedef enum {
ITTI_MSG_TYPE_NONE = -1,
ITTI_MSG_TYPE_FIRST = 0,
ASYNC_SHELL_CMD = ITTI_MSG_TYPE_FIRST,
NEW_SCTP_ASSOCIATION,
NG_SETUP_REQ,
TIME_OUT,
HEALTH_PING,
TERMINATE,
ITTI_MSG_TYPE_MAX
} itti_msg_type_t;
typedef unsigned long message_number_t;
class itti_msg {
public:
itti_msg();
itti_msg(const itti_msg_type_t msg_type, const task_id_t origin, const task_id_t destination);
itti_msg(const itti_msg& i);
itti_msg& operator=(itti_msg other)
{
std::swap(msg_num, other.msg_num);
std::swap(origin, other.origin);
std::swap(destination, other.destination);
std::swap(msg_type, other.msg_type);
return *this;
}
virtual ~itti_msg() = default;
static const char* get_msg_name();
message_number_t msg_num;
task_id_t origin;
task_id_t destination;
itti_msg_type_t msg_type;
};
class itti_msg_timeout : public itti_msg {
public:
itti_msg_timeout(const task_id_t origin, const task_id_t destination, uint32_t timer_id, uint64_t arg1_user, uint64_t arg2_user):
itti_msg(TIME_OUT, origin, destination), timer_id(timer_id), arg1_user(arg1_user), arg2_user(arg2_user) {}
itti_msg_timeout(const itti_msg_timeout& i) : itti_msg(i), timer_id(i.timer_id), arg1_user(i.arg1_user), arg2_user(i.arg2_user) {}
static const char* get_msg_name() {return "TIME_OUT";};
uint32_t timer_id;
uint64_t arg1_user;
uint64_t arg2_user;
};
class itti_msg_ping : public itti_msg {
public:
itti_msg_ping(const task_id_t origin, const task_id_t destination, uint32_t seq): itti_msg(HEALTH_PING, origin, destination), seq(seq) {}
itti_msg_ping(const itti_msg_ping& i) : itti_msg(i), seq(i.seq) {}
static const char* get_msg_name() {return "HEALTH_PING";};
uint32_t seq;
};
class itti_msg_terminate : public itti_msg {
public:
itti_msg_terminate(const task_id_t origin, const task_id_t destination):
itti_msg(TERMINATE, origin, destination) {}
itti_msg_terminate(const itti_msg_terminate& i) : itti_msg(i) {}
static const char* get_msg_name() {return "TERMINATE";};
};
#endif /* SRC_ITTI_ITTI_MSG_HPP_INCLUDED_ */
#include <iostream>
#include <thread>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "logger.hpp"
#include "options.hpp"
#include "amf_config.hpp"
#include "ngap_app.hpp"
#include "itti.hpp"
using namespace std;
using namespace config;
using namespace ngap;
amf_config amf_cfg;
ngap_app * ngap_inst = NULL;
itti_mw *itti_inst = nullptr;
void amf_ngap_app_task(void*){
const task_id_t task_id = TASK_NGAP_APP;
itti_inst->notify_task_ready(task_id);
Logger::itti().debug("task(%d) ready",TASK_NGAP_APP);
}
int main(int argc, char **argv){
srand (time(NULL));
if(!Options::parse(argc, argv)){
cout<<"Options::parse() failed"<<endl;
return 1;
}
Logger::init( "amf" , Options::getlogStdout() , Options::getlogRotFilelog());
Logger::amf_app().startup("Options parsed!");
amf_cfg.load(Options::getlibconfigConfig());
amf_cfg.display();
//ngap_inst = new ngap_app("10.103.238.20",38412);
itti_inst = new itti_mw();
//itti_inst->start(amf_cfg.itti.itti_timer_sched_params);
itti_inst->create_task(TASK_NGAP_APP, amf_ngap_app_task,nullptr);
Logger::amf_app().debug("Initiating Done!");
pause();
return 0;
}
#ifndef _ITTI_MSG_N2_H_
#define _ITTI_MSG_N2_H_
#include "itti_msg.hpp"
class itti_msg_n2 : public itti_msg{
public:
itti_msg_n2(const itti_msg_type_t msg_type, const task_id_t origin, const task_id_t destination):itti_msg(msg_type,origin,destination){
}
itti_msg_n2(const itti_msg_n2& i) : itti_msg(i){
assoc_id = i.assoc_id;
stream = i.stream;
}
sctp_assoc_id_t assoc_id;
sctp_stream_id_t stream;
//NGSetupRequestMsg * ngSetupReq;
};
class itti_new_sctp_association : public itti_msg_n2{
public:
itti_new_sctp_association(const task_id_t origin, const task_id_t destination) : itti_msg_n2(NEW_SCTP_ASSOCIATION, origin, destination){}
};
class itti_ng_setup_request : public itti_msg_n2{
public:
itti_ng_setup_request(const task_id_t origin, const task_id_t destination):itti_msg_n2(NG_SETUP_REQ,origin,destination){}
itti_ng_setup_request(const itti_ng_setup_request &i) : itti_msg_n2(i){
}
private:
//NGSetupRequestMsg * ngSetupReq;
};
#endif
#ifndef _AMF_NAS_CONTEXT_H_
#define _AMF_NAS_CONTEXT_H_
#include <stdint.h>
class nas_context{
public:
long amf_ue_ngap_id;
uint32_t ran_ue_ngap_id;
};
#endif
cmake_minimum_required (VERSION 3.0.2)
project(OpenAirInterface)
macro(add_list_string_option name val helpstr)
if(DEFINED ${name})
set(value ${${name}})
else(DEFINED ${name})
set(value ${val})
endif()
set(${name} ${value} CACHE STRING "${helpstr}")
set_property(CACHE ${name} PROPERTY STRINGS ${ARGN})
if(NOT "${value}" STREQUAL "False")
add_definitions("-D${name}=\"${value}\"")
endif()
endmacro(add_list_string_option)
SET(STATIC_LINKING FALSE CACHE BOOL "Build a static binary?")
IF(STATIC_LINKING)
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
ENDIF(STATIC_LINKING)
add_list_string_option(CMAKE_BUILD_TYPE "RelWithDebInfo" "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." Debug Release
RelWithDebInfo MinSizeRel)
Message("Build type is ${CMAKE_BUILD_TYPE}")
if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
add_boolean_option(LOG_OAI True "Thread safe logging API")
add_boolean_option(LOG_OAI_MINIMAL True "Thread safe logging API, log only levels above NOTICE")
SET(ASAN asan)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_boolean_option(LOG_OAI True "Thread safe logging API")
SET(ASAN asan)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE "MinSizeRel")
endif()
Message("Build type is ${CMAKE_BUILD_TYPE}")
Message("Architecture is ${CMAKE_SYSTEM_PROCESSOR}")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
set(C_FLAGS_PROCESSOR "-gdwarf-2 -mfloat-abi=hard -mfpu=neon -lgcc -lrt")
else (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
set(C_FLAGS_PROCESSOR "-msse4.2")
endif()
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} ${C_FLAGS_PROCESSOR} -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC ")
# add autoTOOLS definitions that were maybe used!
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP")
add_definitions(-DCMAKER)
add_definitions(-DBSTRLIB_CAN_USE_STL=1 -DBSTRLIB_CAN_USE_IOSTREAM=1 -DBSTRLIB_THROWS_EXCEPTIONS=1)
if(STATIC_LINKING)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fno-omit-frame-pointer")
else (STATIC_LINKING)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fsanitize=address -fno-omit-frame-pointer")
endif(STATIC_LINKING)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O2 -fno-omit-frame-pointer -s -DINFO_IS_ON=1 ")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -O2 -DINFO_IS_ON=1 ")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS} -Os -s -DTRACE_IS_ON=1 -DDEBUG_IS_ON=1 -DINFO_IS_ON=1")
if(STATIC_LINKING)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -std=c++17 -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fno-omit-frame-pointer -DBUPT=1 -DEURECOM=0")
else(STATIC_LINKING)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -std=c++17 -g -fstack-protector-all -DMALLOC_CHECK_=3 -DINFO_IS_ON=1 -DDEBUG_IS_ON=1 -DTRACE_IS_ON=1 -O0 -fsanitize=address -fno-omit-frame-pointer -DBUPT=1 -DEURECOM=0")
endif(STATIC_LINKING)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -std=c++17 -O2 -fno-omit-frame-pointer -s -DINFO_IS_ON=1 -DBUPT=1 -DEURECOM=0")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -std=c++17 -g -O2 -DINFO_IS_ON=1 -DBUPT=1 -DEURECOM=0")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -std=c++17 -Os -s -DTRACE_IS_ON=1 -DDEBUG_IS_ON=1 -DINFO_IS_ON=1")
set(CMAKE_MODULE_PATH "${OPENAIRCN_DIR}/build/cmake_modules" "${CMAKE_MODULE_PATH}")
include(FindPkgConfig)
message("${OPENAIRCN_DIR}/build/cmake_modules")
include_directories(${SRC_TOP_DIR}/oai-amf)
include_directories(${SRC_TOP_DIR}/amf-app)
include_directories(${SRC_TOP_DIR}/../build/ext/spdlog/include)
### for common
include_directories(${SRC_TOP_DIR}/common)
file(GLOB COMMON_SRC ${SRC_TOP_DIR}/common/conversions.cpp)
### end for common
### for utils/bstr
include_directories(${SRC_TOP_DIR}/utils/bstr)
file(GLOB BSTR_SRC ${SRC_TOP_DIR}/utils/bstr/bstrlib.c)
##end for utils/bstr
### for sctp
include_directories(${SRC_TOP_DIR}/sctp)
file(GLOB SCTP_SRC ${SRC_TOP_DIR}/sctp/sctp_server.cpp)
#end for sctp
### for ngap
include_directories(${SRC_TOP_DIR}/ngap/ngap_app)
file(GLOB NGAP_SRC ${SRC_TOP_DIR}/ngap/ngap_app/ngap_app.cpp)
###end for ngap
### for log
add_library( LOG STATIC
${SRC_TOP_DIR}/common/logger.cpp)
add_library( OPTIONS STATIC
${SRC_TOP_DIR}/oai-amf/options.cpp)
###end for log
### for config
add_library( CONFIGS STATIC
${SRC_TOP_DIR}/amf-app/amf_config.cpp)
pkg_search_module(CONFIG REQUIRED libconfig++)
include_directories(${CONFIG_INCLUDE_DIRS})
### end for config
add_executable(amf
${SRC_TOP_DIR}/ngap/main.cpp
${COMMON_SRC} ${BSTR_SRC} ${SCTP_SRC} ${NGAP_SRC}
)
# LOG from oai-amf/CMakeLists.txt
target_link_libraries(amf -Wl,--start-group LOG OPTIONS CONFIGS config++ sctp pthread)
This diff is collapsed.
/*-
* Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#ifndef ASN_TYPE_ANY_H
#define ASN_TYPE_ANY_H
#include <OCTET_STRING.h> /* Implemented via OCTET STRING type */
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ANY {
uint8_t *buf; /* BER-encoded ANY contents */
int size; /* Size of the above buffer */
asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */
} ANY_t;
extern asn_TYPE_descriptor_t asn_DEF_ANY;
extern asn_TYPE_operation_t asn_OP_ANY;
extern asn_OCTET_STRING_specifics_t asn_SPC_ANY_specs;
asn_struct_free_f ANY_free;
asn_struct_print_f ANY_print;
ber_type_decoder_f ANY_decode_ber;
der_type_encoder_f ANY_encode_der;
xer_type_encoder_f ANY_encode_xer;
per_type_decoder_f ANY_decode_uper;
per_type_encoder_f ANY_encode_uper;
per_type_decoder_f ANY_decode_aper;
per_type_encoder_f ANY_encode_aper;
#define ANY_free OCTET_STRING_free
#define ANY_print OCTET_STRING_print
#define ANY_compare OCTET_STRING_compare
#define ANY_constraint asn_generic_no_constraint
#define ANY_decode_ber OCTET_STRING_decode_ber
#define ANY_encode_der OCTET_STRING_encode_der
#define ANY_decode_xer OCTET_STRING_decode_xer_hex
/******************************
* Handy conversion routines. *
******************************/
/* Convert another ASN.1 type into the ANY. This implies DER encoding. */
int ANY_fromType(ANY_t *, asn_TYPE_descriptor_t *td, void *struct_ptr);
int ANY_fromType_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr);
ANY_t *ANY_new_fromType(asn_TYPE_descriptor_t *td, void *struct_ptr);
ANY_t *ANY_new_fromType_aper(asn_TYPE_descriptor_t *td, void *sptr);
/* Convert the contents of the ANY type into the specified type. */
int ANY_to_type(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr);
int ANY_to_type_aper(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr);
#define ANY_fromBuf(s, buf, size) OCTET_STRING_fromBuf((s), (buf), (size))
#define ANY_new_fromBuf(buf, size) OCTET_STRING_new_fromBuf( \
&asn_DEF_ANY, (buf), (size))
#ifdef __cplusplus
}
#endif
#endif /* ASN_TYPE_ANY_H */
This diff is collapsed.
/*-
* Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#ifndef _BIT_STRING_H_
#define _BIT_STRING_H_
#include <OCTET_STRING.h> /* Some help from OCTET STRING */
#ifdef __cplusplus
extern "C" {
#endif
typedef struct BIT_STRING_s {
uint8_t *buf; /* BIT STRING body */
size_t size; /* Size of the above buffer */
int bits_unused;/* Unused trailing bits in the last octet (0..7) */
asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */
} BIT_STRING_t;
extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING;
extern asn_TYPE_operation_t asn_OP_BIT_STRING;
extern asn_OCTET_STRING_specifics_t asn_SPC_BIT_STRING_specs;
asn_struct_print_f BIT_STRING_print; /* Human-readable output */
asn_struct_compare_f BIT_STRING_compare;
asn_constr_check_f BIT_STRING_constraint;
xer_type_encoder_f BIT_STRING_encode_xer;
oer_type_decoder_f BIT_STRING_decode_oer;
oer_type_encoder_f BIT_STRING_encode_oer;
per_type_decoder_f BIT_STRING_decode_uper;
per_type_encoder_f BIT_STRING_encode_uper;
asn_random_fill_f BIT_STRING_random_fill;
#define BIT_STRING_free OCTET_STRING_free
#define BIT_STRING_decode_ber OCTET_STRING_decode_ber
#define BIT_STRING_encode_der OCTET_STRING_encode_der
#define BIT_STRING_decode_xer OCTET_STRING_decode_xer_binary
#define BIT_STRING_decode_aper OCTET_STRING_decode_aper
#define BIT_STRING_encode_aper OCTET_STRING_encode_aper
#ifdef __cplusplus
}
#endif
#endif /* _BIT_STRING_H_ */
/*
* Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#ifndef ASN_DISABLE_OER_SUPPORT
#include <asn_internal.h>
#include <BIT_STRING.h>
#include <errno.h>
asn_dec_rval_t
BIT_STRING_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints, void **sptr,
const void *ptr, size_t size) {
BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
const asn_oer_constraints_t *cts =
constraints ? constraints : td->encoding_constraints.oer_constraints;
ssize_t ct_size = cts ? cts->size : -1;
asn_dec_rval_t rval = {RC_OK, 0};
size_t expected_length = 0;
(void)opt_codec_ctx;
if(!st) {
st = (BIT_STRING_t *)(*sptr = CALLOC(1, sizeof(*st)));
if(!st) ASN__DECODE_FAILED;
}
if(ct_size >= 0) {
expected_length = (ct_size + 7) >> 3;
st->bits_unused = (8 - (ct_size & 7)) & 7;
} else {
/*
* X.696 (08/2015) #13.3.1
* Encode length determinant as _number of octets_, but only
* if upper bound is not equal to lower bound.
*/
ssize_t len_len = oer_fetch_length(ptr, size, &expected_length);
if(len_len > 0) {
ptr = (const char *)ptr + len_len;
size -= len_len;
} else if(len_len == 0) {
ASN__DECODE_STARVED;
} else if(len_len < 0) {
ASN__DECODE_FAILED;
}
if(expected_length < 1) {
ASN__DECODE_FAILED;
} else if(expected_length > size) {
ASN__DECODE_STARVED;
}
st->bits_unused = ((const uint8_t *)ptr)[0];
if(st->bits_unused & ~7) {
ASN_DEBUG("%s: unused bits outside of 0..7 range", td->name);
ASN__DECODE_FAILED;
}
ptr = (const char *)ptr + 1;
size--;
expected_length--;
rval.consumed = len_len + 1;
}
if(size < expected_length) {
ASN__DECODE_STARVED;
} else {
uint8_t *buf = MALLOC(expected_length + 1);
if(buf == NULL) {
ASN__DECODE_FAILED;
} else {
memcpy(buf, ptr, expected_length);
buf[expected_length] = '\0';
}
FREEMEM(st->buf);
st->buf = buf;
st->size = expected_length;
if(expected_length > 0) {
buf[expected_length - 1] &= (0xff << st->bits_unused);
}
rval.consumed += expected_length;
return rval;
}
}
/*
* Encode as Canonical OER.
*/
asn_enc_rval_t
BIT_STRING_encode_oer(const asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints,
const void *sptr, asn_app_consume_bytes_f *cb,
void *app_key) {
const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
asn_enc_rval_t erval = {0, 0, 0};
const asn_oer_constraints_t *cts =
constraints ? constraints : td->encoding_constraints.oer_constraints;
ssize_t ct_size = cts ? cts->size : -1;
size_t trailing_zeros = 0;
int fix_last_byte = 0;
if(!st) ASN__ENCODE_FAILED;
if(st->bits_unused & ~7) {
ASN_DEBUG("BIT STRING unused bits %d out of 0..7 range",
st->bits_unused);
ASN__ENCODE_FAILED;
}
if(st->bits_unused && !(st->size && st->buf)) {
ASN_DEBUG("BIT STRING %s size 0 can't support unused bits %d", td->name,
st->bits_unused);
ASN__ENCODE_FAILED;
}
if(ct_size >= 0) {
size_t ct_bytes = (ct_size + 7) >> 3;
if(st->size > ct_bytes) {
ASN_DEBUG("More bits in BIT STRING %s (%" ASN_PRI_SSIZE ") than constrained %" ASN_PRI_SSIZE "",
td->name, 8 * st->size - st->bits_unused, ct_size);
ASN__ENCODE_FAILED;
}
trailing_zeros = ct_bytes - st->size; /* Allow larger constraint */
} else {
uint8_t ub = st->bits_unused & 7;
ssize_t len_len = oer_serialize_length(1 + st->size, cb, app_key);
if(len_len < 0) ASN__ENCODE_FAILED;
if(cb(&ub, 1, app_key) < 0) {
ASN__ENCODE_FAILED;
}
erval.encoded += len_len + 1;
}
if(st->bits_unused) {
if(st->buf[st->size - 1] & (0xff << st->bits_unused)) {
fix_last_byte = 1;
}
}
if(cb(st->buf, st->size - fix_last_byte, app_key) < 0) {
ASN__ENCODE_FAILED;
}
if(fix_last_byte) {
uint8_t b = st->buf[st->size - 1] & (0xff << st->bits_unused);
if(cb(&b, 1, app_key) < 0) {
ASN__ENCODE_FAILED;
}
}
erval.encoded += st->size;
if(trailing_zeros) {
static uint8_t zeros[16];
while(trailing_zeros > 0) {
int ret;
if(trailing_zeros < sizeof(zeros)) {
ret = cb(zeros, trailing_zeros, app_key);
erval.encoded += trailing_zeros;
} else {
ret = cb(zeros, sizeof(zeros), app_key);
erval.encoded += sizeof(zeros);
}
if(ret < 0) ASN__ENCODE_FAILED;
}
}
return erval;
}
#endif /* ASN_DISABLE_OER_SUPPORT */
This diff is collapsed.
/*-
* Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#ifndef _INTEGER_H_
#define _INTEGER_H_
#include <asn_application.h>
#include <asn_codecs_prim.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef ASN__PRIMITIVE_TYPE_t INTEGER_t;
extern asn_TYPE_descriptor_t asn_DEF_INTEGER;
extern asn_TYPE_operation_t asn_OP_INTEGER;
/* Map with <tag> to integer value association */
typedef struct asn_INTEGER_enum_map_s {
long nat_value; /* associated native integer value */
size_t enum_len; /* strlen("tag") */
const char *enum_name; /* "tag" */
} asn_INTEGER_enum_map_t;
/* This type describes an enumeration for INTEGER and ENUMERATED types */
typedef struct asn_INTEGER_specifics_s {
const asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */
const unsigned int *enum2value; /* "tag" => N; sorted by tag */
int map_count; /* Elements in either map */
int extension; /* This map is extensible */
int strict_enumeration; /* Enumeration set is fixed */
int field_width; /* Size of native integer */
int field_unsigned; /* Signed=0, unsigned=1 */
} asn_INTEGER_specifics_t;
#define INTEGER_free ASN__PRIMITIVE_TYPE_free
#define INTEGER_decode_ber ber_decode_primitive
#define INTEGER_constraint asn_generic_no_constraint
asn_struct_print_f INTEGER_print;
asn_struct_compare_f INTEGER_compare;
der_type_encoder_f INTEGER_encode_der;
xer_type_decoder_f INTEGER_decode_xer;
xer_type_encoder_f INTEGER_encode_xer;
oer_type_decoder_f INTEGER_decode_oer;
oer_type_encoder_f INTEGER_encode_oer;
per_type_decoder_f INTEGER_decode_uper;
per_type_encoder_f INTEGER_encode_uper;
per_type_decoder_f INTEGER_decode_aper;
per_type_encoder_f INTEGER_encode_aper;
asn_random_fill_f INTEGER_random_fill;
/***********************************
* Some handy conversion routines. *
***********************************/
/*
* Natiwe size-independent conversion of native integers to/from INTEGER.
* (l_size) is in bytes.
* Returns 0 if it was possible to convert, -1 otherwise.
* -1/EINVAL: Mandatory argument missing
* -1/ERANGE: Value encoded is out of range for long representation
* -1/ENOMEM: Memory allocation failed (in asn_*2INTEGER()).
*/
int asn_INTEGER2imax(const INTEGER_t *i, intmax_t *l);
int asn_INTEGER2umax(const INTEGER_t *i, uintmax_t *l);
int asn_imax2INTEGER(INTEGER_t *i, intmax_t l);
int asn_umax2INTEGER(INTEGER_t *i, uintmax_t l);
/*
* Size-specific conversion helpers.
*/
int asn_INTEGER2long(const INTEGER_t *i, long *l);
int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l);
int asn_long2INTEGER(INTEGER_t *i, long l);
int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l);
int asn_int642INTEGER(INTEGER_t *i, int64_t l);
int asn_uint642INTEGER(INTEGER_t *i, uint64_t l);
/* A version of strtol/strtoimax(3) with nicer error reporting. */
enum asn_strtox_result_e {
ASN_STRTOX_ERROR_RANGE = -3, /* Input outside of supported numeric range */
ASN_STRTOX_ERROR_INVAL = -2, /* Invalid data encountered (e.g., "+-") */
ASN_STRTOX_EXPECT_MORE = -1, /* More data expected (e.g. "+") */
ASN_STRTOX_OK = 0, /* Conversion succeded, number ends at (*end) */
ASN_STRTOX_EXTRA_DATA = 1 /* Conversion succeded, but the string has extra stuff */
};
enum asn_strtox_result_e asn_strtol_lim(const char *str, const char **end,
long *l);
enum asn_strtox_result_e asn_strtoul_lim(const char *str, const char **end,
unsigned long *l);
enum asn_strtox_result_e asn_strtoimax_lim(const char *str, const char **end,
intmax_t *l);
enum asn_strtox_result_e asn_strtoumax_lim(const char *str, const char **end,
uintmax_t *l);
/*
* Convert the integer value into the corresponding enumeration map entry.
*/
const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(
const asn_INTEGER_specifics_t *specs, long value);
#ifdef __cplusplus
}
#endif
#endif /* _INTEGER_H_ */
/*
* Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#ifndef ASN_DISABLE_OER_SUPPORT
#include <asn_internal.h>
#include <INTEGER.h>
#include <errno.h>
asn_dec_rval_t
INTEGER_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints, void **sptr,
const void *ptr, size_t size) {
const asn_INTEGER_specifics_t *specs =
(const asn_INTEGER_specifics_t *)td->specifics;
asn_dec_rval_t rval = {RC_OK, 0};
INTEGER_t *st = (INTEGER_t *)*sptr;
struct asn_oer_constraint_number_s ct = {0, 0};
size_t req_bytes;
(void)opt_codec_ctx;
(void)specs;
if(!st) {
st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
if(!st) ASN__DECODE_FAILED;
}
FREEMEM(st->buf);
st->buf = 0;
st->size = 0;
if(!constraints) constraints = td->encoding_constraints.oer_constraints;
if(constraints) ct = constraints->value;
if(ct.width) {
req_bytes = ct.width;
} else {
/* No lower bound and no upper bound, effectively */
ssize_t consumed = oer_fetch_length(ptr, size, &req_bytes);
if(consumed == 0) {
ASN__DECODE_STARVED;
} else if(consumed == -1) {
ASN__DECODE_FAILED;
}
rval.consumed += consumed;
ptr = (const char *)ptr + consumed;
size -= consumed;
}
if(req_bytes > size) {
ASN__DECODE_STARVED;
}
if(ct.positive) {
/* X.969 08/2015 10.2(a) */
unsigned msb; /* Most significant bit */
size_t useful_size;
/* Check most significant bit */
msb = *(const uint8_t *)ptr >> 7; /* yields 0 or 1 */
useful_size = msb + req_bytes;
st->buf = (uint8_t *)MALLOC(useful_size + 1);
if(!st->buf) {
ASN__DECODE_FAILED;
}
/*
* Record a large unsigned in a way not to confuse it
* with signed value.
*/
st->buf[0] = '\0';
memcpy(st->buf + msb, ptr, req_bytes);
st->buf[useful_size] = '\0'; /* Just in case, 0-terminate */
st->size = useful_size;
rval.consumed += req_bytes;
return rval;
} else {
/* X.969 08/2015 10.2(b) */
st->buf = (uint8_t *)MALLOC(req_bytes + 1);
if(!st->buf) {
ASN__DECODE_FAILED;
}
memcpy(st->buf, ptr, req_bytes);
st->buf[req_bytes] = '\0'; /* Just in case, 0-terminate */
st->size = req_bytes;
rval.consumed += req_bytes;
return rval;
}
}
/*
* Encode as Canonical OER.
*/
asn_enc_rval_t
INTEGER_encode_oer(const asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints, const void *sptr,
asn_app_consume_bytes_f *cb, void *app_key) {
const INTEGER_t *st = sptr;
asn_enc_rval_t er;
struct asn_oer_constraint_number_s ct = {0, 0};
const uint8_t *buf;
const uint8_t *end;
size_t useful_bytes;
size_t req_bytes = 0;
int sign = 0;
if(!st || st->size == 0) ASN__ENCODE_FAILED;
if(!constraints) constraints = td->encoding_constraints.oer_constraints;
if(constraints) ct = constraints->value;
er.encoded = 0;
buf = st->buf;
end = buf + st->size;
sign = (buf && buf < end) ? buf[0] & 0x80 : 0;
/* Ignore 9 leading zeroes or ones */
if(ct.positive) {
if(sign) {
/* The value given is a signed value. Can't proceed. */
ASN__ENCODE_FAILED;
}
/* Remove leading zeros. */
for(; buf + 1 < end; buf++) {
if(buf[0] != 0x0) break;
}
} else {
for(; buf + 1 < end; buf++) {
if(buf[0] == 0x0 && (buf[1] & 0x80) == 0) {
continue;
} else if(buf[0] == 0xff && (buf[1] & 0x80) != 0) {
continue;
}
break;
}
}
useful_bytes = end - buf;
if(ct.width) {
req_bytes = ct.width;
} else {
ssize_t r = oer_serialize_length(useful_bytes, cb, app_key);
if(r < 0) {
ASN__ENCODE_FAILED;
}
er.encoded += r;
req_bytes = useful_bytes;
}
if(req_bytes < useful_bytes) {
ASN__ENCODE_FAILED;
}
er.encoded += req_bytes;
for(; req_bytes > useful_bytes; req_bytes--) {
if(cb(sign?"\xff":"\0", 1, app_key) < 0) {
ASN__ENCODE_FAILED;
}
}
if(cb(buf, useful_bytes, app_key) < 0) {
ASN__ENCODE_FAILED;
}
ASN__ENCODED_OK(er);
}
#endif /* ASN_DISABLE_OER_SUPPORT */
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
/*
* This type differs from the standard ENUMERATED in that it is modelled using
* the fixed machine type (long, int, short), so it can hold only values of
* limited length. There is no type (i.e., NativeEnumerated_t, any integer type
* will do).
* This type may be used when integer range is limited by subtype constraints.
*/
#ifndef _NativeEnumerated_H_
#define _NativeEnumerated_H_
#include <NativeInteger.h>
#ifdef __cplusplus
extern "C" {
#endif
extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated;
extern asn_TYPE_operation_t asn_OP_NativeEnumerated;
xer_type_encoder_f NativeEnumerated_encode_xer;
oer_type_decoder_f NativeEnumerated_decode_oer;
oer_type_encoder_f NativeEnumerated_encode_oer;
per_type_decoder_f NativeEnumerated_decode_uper;
per_type_encoder_f NativeEnumerated_encode_uper;
per_type_decoder_f NativeEnumerated_decode_aper;
per_type_encoder_f NativeEnumerated_encode_aper;
#define NativeEnumerated_free NativeInteger_free
#define NativeEnumerated_print NativeInteger_print
#define NativeEnumerated_compare NativeInteger_compare
#define NativeEnumerated_random_fill NativeInteger_random_fill
#define NativeEnumerated_constraint asn_generic_no_constraint
#define NativeEnumerated_decode_ber NativeInteger_decode_ber
#define NativeEnumerated_encode_der NativeInteger_encode_der
#define NativeEnumerated_decode_xer NativeInteger_decode_xer
#ifdef __cplusplus
}
#endif
#endif /* _NativeEnumerated_H_ */
This diff is collapsed.
This diff is collapsed.
/*-
* Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
/*
* This type differs from the standard INTEGER in that it is modelled using
* the fixed machine type (long, int, short), so it can hold only values of
* limited length. There is no type (i.e., NativeInteger_t, any integer type
* will do).
* This type may be used when integer range is limited by subtype constraints.
*/
#ifndef _NativeInteger_H_
#define _NativeInteger_H_
#include <asn_application.h>
#include <INTEGER.h>
#ifdef __cplusplus
extern "C" {
#endif
extern asn_TYPE_descriptor_t asn_DEF_NativeInteger;
extern asn_TYPE_operation_t asn_OP_NativeInteger;
asn_struct_free_f NativeInteger_free;
asn_struct_print_f NativeInteger_print;
asn_struct_compare_f NativeInteger_compare;
ber_type_decoder_f NativeInteger_decode_ber;
der_type_encoder_f NativeInteger_encode_der;
xer_type_decoder_f NativeInteger_decode_xer;
xer_type_encoder_f NativeInteger_encode_xer;
oer_type_decoder_f NativeInteger_decode_oer;
oer_type_encoder_f NativeInteger_encode_oer;
per_type_decoder_f NativeInteger_decode_uper;
per_type_encoder_f NativeInteger_encode_uper;
per_type_decoder_f NativeInteger_decode_aper;
per_type_encoder_f NativeInteger_encode_aper;
asn_random_fill_f NativeInteger_random_fill;
#define NativeInteger_constraint asn_generic_no_constraint
#ifdef __cplusplus
}
#endif
#endif /* _NativeInteger_H_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment