Commit 1e0941d0 authored by gauthier's avatar gauthier

utils

parent a7358548
/*
* 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 async_shell_cmd.cpp
\brief
\author Lionel GAUTHIER
\date 2017
\email: lionel.gauthier@eurecom.fr
*/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <inttypes.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include "itti.hpp"
#include "async_shell_cmd.hpp"
#include "itti_async_shell_cmd.hpp"
#include "logger.hpp"
#include "common_defs.h"
#include <stdexcept>
using namespace oai::cn::core::itti;
using namespace oai::cn::util;
;
extern itti_mw *itti_inst;
void async_cmd_task (void*);
//------------------------------------------------------------------------------
void async_cmd_task (void*)
{
const task_id_t task_id = TASK_ASYNC_SHELL_CMD;
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 ASYNC_SHELL_CMD:
if (itti_async_shell_cmd* to = dynamic_cast<itti_async_shell_cmd*>(msg)) {
int rc = system ((const char*)to->system_command.c_str());
if (rc) {
Logger::async_cmd().error( "Failed cmd from %d: %s ", to->origin, (const char*)to->system_command.c_str());
if (to->is_abort_on_error) {
Logger::async_cmd().error( "Terminate cause failed cmd %s at %s:%d", to->system_command.c_str(), to->src_file.c_str(), to->src_line);
itti_inst->send_terminate_msg(to->origin);
}
}
}
break;
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
Logger::async_cmd().info( "TIME-OUT event timer id %d", to->timer_id);
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
Logger::async_cmd().info( "Received terminate message");
return;
}
break;
default:
Logger::sgwc_app().info( "no handler for msg type %d", msg->msg_type);
}
} while (true);
}
//------------------------------------------------------------------------------
async_shell_cmd::async_shell_cmd (void)
{
Logger::async_cmd().startup( "Starting..." );
if (itti_inst->create_task(TASK_ASYNC_SHELL_CMD, async_cmd_task, nullptr) ) {
Logger::async_cmd().error( "Cannot create task TASK_ASYNC_SHELL_CMD" );
throw std::runtime_error( "Cannot create task TASK_ASYNC_SHELL_CMD" );
}
Logger::async_cmd().startup( "Started" );
}
//------------------------------------------------------------------------------
int async_shell_cmd::run_command (const task_id_t sender_itti_task, const bool is_abort_on_error, const char* src_file, const int src_line, const std::string& cmd_str)
{
itti_async_shell_cmd cmd(sender_itti_task, TASK_ASYNC_SHELL_CMD, cmd_str, is_abort_on_error, src_file, src_line);
std::shared_ptr<itti_async_shell_cmd> msg = std::make_shared<itti_async_shell_cmd>(cmd);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::async_cmd().error( "Could not send ITTI message to task TASK_ASYNC_SHELL_CMD");
return RETURNerror;
}
return RETURNok;
}
/*
* 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 async_shell_cmd.hpp
\brief We still use some unix commands for convenience, and we did not have to replace them by system calls
\ Instead of calling C system(...) that can take a lot of time (creation of a process, etc), in many cases
\ it doesn't hurt to do this asynchronously, may be we must tweak thread priority, pin it to a CPU, etc (TODO later)
\author Lionel GAUTHIER
\date 2017
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_ASYNC_SHELL_CMD_HPP_SEEN
#define FILE_ASYNC_SHELL_CMD_HPP_SEEN
#include "itti_msg.hpp"
#include <string>
#include <thread>
namespace oai::cn::util {
class async_shell_cmd {
private:
std::thread::id thread_id;
std::thread thread;
public:
async_shell_cmd();
~async_shell_cmd() {}
async_shell_cmd(async_shell_cmd const&) = delete;
void operator=(async_shell_cmd const&) = delete;
int run_command (const core::itti::task_id_t sender_itti_task, const bool is_abort_on_error, const char* src_file, const int src_line, const std::string& cmd_str);
};
}
#endif /* FILE_ASYNC_SHELL_CMD_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 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>
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
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
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;
}
}
//------------------------------------------------------------------------------
imsi64_t imsi_to_imsi64(imsi_t * const imsi)
{
imsi64_t imsi64 = INVALID_IMSI64;
if (imsi) {
imsi64 = 0;
for (int i=0; i < IMSI_BCD8_SIZE; i++) {
uint8_t d2 = imsi->u.value[i];
uint8_t d1 = (d2 & 0xf0) >> 4;
d2 = d2 & 0x0f;
if (10 > d1) {
imsi64 = imsi64*10 + d1;
if (10 > d2) {
imsi64 = imsi64*10 + d2;
} else {
break;
}
} else {
break;
}
}
}
return imsi64;
}
//------------------------------------------------------------------------------
void paa_to_pfcp_ue_ip_address(const oai::cn::core::paa_t& paa, oai::cn::core::pfcp::ue_ip_address_t& ue_ip_address)
{
switch (paa.pdn_type.pdn_type) {
case oai::cn::core::PDN_TYPE_E_IPV4:
ue_ip_address.v4 = 1;
ue_ip_address.ipv4_address = paa.ipv4_address;
break;
case oai::cn::core::PDN_TYPE_E_IPV6:
ue_ip_address.v6 = 1;
ue_ip_address.ipv6_address = paa.ipv6_address;
break;
case oai::cn::core::PDN_TYPE_E_IPV4V6:
ue_ip_address.v4 = 1;
ue_ip_address.v6 = 1;
ue_ip_address.ipv4_address = paa.ipv4_address;
ue_ip_address.ipv6_address = paa.ipv6_address;
break;
case oai::cn::core::PDN_TYPE_E_NON_IP:
default:
;
}
}
//------------------------------------------------------------------------------
void pdn_ip_to_pfcp_ue_ip_address(const oai::cn::core::pdn_type_t& pdn_type,
const struct in_addr& ipv4_address,
const struct in6_addr ipv6_address,
oai::cn::core::pfcp::ue_ip_address_t& ue_ip_address)
{
switch (pdn_type.pdn_type) {
case oai::cn::core::PDN_TYPE_E_IPV4:
ue_ip_address.v4 = 1;
ue_ip_address.ipv4_address = ipv4_address;
break;
case oai::cn::core::PDN_TYPE_E_IPV6:
ue_ip_address.v6 = 1;
ue_ip_address.ipv6_address = ipv6_address;
break;
case oai::cn::core::PDN_TYPE_E_IPV4V6:
ue_ip_address.v4 = 1;
ue_ip_address.v6 = 1;
ue_ip_address.ipv4_address = ipv4_address;
ue_ip_address.ipv6_address = ipv6_address;
break;
case oai::cn::core::PDN_TYPE_E_NON_IP:
default:
;
}
}
/*
* 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 "3gpp_23.003.h"
#include "3gpp_24.008.h"
#include "3gpp_29.274.h"
#include "3gpp_29.244.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Endianness conversions for 16 and 32 bits integers from host to network order */
#if (BYTE_ORDER == LITTLE_ENDIAN)
# define hton_int32(x) \
(((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | \
((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24))
# define hton_int16(x) \
(((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)
# define ntoh_int32_buf(bUF) \
((*(bUF)) << 24) | ((*((bUF) + 1)) << 16) | ((*((bUF) + 2)) << 8) \
| (*((bUF) + 3))
#else
# define hton_int32(x) (x)
# define hton_int16(x) (x)
#endif
#define IN_ADDR_TO_BUFFER(X,bUFF) INT32_TO_BUFFER((X).s_addr,(char*)bUFF)
#define BUFFER_TO_IN_ADDR(bUFF, X) \
do { \
(X).s_addr = (((uint8_t*)(bUFF))[0]) | \
(((uint8_t*)(bUFF))[1] << 8) | \
(((uint8_t*)(bUFF))[2] << 16) | \
(((uint8_t*)(bUFF))[3] << 24); \
} while(0)
#define IN6_ADDR_TO_BUFFER(X,bUFF) \
do { \
((uint8_t*)(bUFF))[0] = (X).s6_addr[0]; \
((uint8_t*)(bUFF))[1] = (X).s6_addr[1]; \
((uint8_t*)(bUFF))[2] = (X).s6_addr[2]; \
((uint8_t*)(bUFF))[3] = (X).s6_addr[3]; \
((uint8_t*)(bUFF))[4] = (X).s6_addr[4]; \
((uint8_t*)(bUFF))[5] = (X).s6_addr[5]; \
((uint8_t*)(bUFF))[6] = (X).s6_addr[6]; \
((uint8_t*)(bUFF))[7] = (X).s6_addr[7]; \
((uint8_t*)(bUFF))[8] = (X).s6_addr[8]; \
((uint8_t*)(bUFF))[9] = (X).s6_addr[9]; \
((uint8_t*)(bUFF))[10] = (X).s6_addr[10]; \
((uint8_t*)(bUFF))[11] = (X).s6_addr[11]; \
((uint8_t*)(bUFF))[12] = (X).s6_addr[12]; \
((uint8_t*)(bUFF))[13] = (X).s6_addr[13]; \
((uint8_t*)(bUFF))[14] = (X).s6_addr[14]; \
((uint8_t*)(bUFF))[15] = (X).s6_addr[15]; \
} while(0)
#define BUFFER_TO_INT8(buf, x) (x = ((buf)[0]))
#define INT8_TO_BUFFER(x, buf) ((buf)[0] = (x))
/* Convert an integer on 16 bits to the given bUFFER */
#define INT16_TO_BUFFER(x, buf) \
do { \
(buf)[0] = (x) >> 8; \
(buf)[1] = (x); \
} while(0)
/* Convert an array of char containing vALUE to x */
#define BUFFER_TO_INT16(buf, x) \
do { \
x = ((buf)[0] << 8) | \
((buf)[1]); \
} while(0)
/* Convert an integer on 32 bits to the given bUFFER */
#define INT32_TO_BUFFER(x, buf) \
do { \
(buf)[0] = (x) >> 24; \
(buf)[1] = (x) >> 16; \
(buf)[2] = (x) >> 8; \
(buf)[3] = (x); \
} while(0)
/* Convert an integer on 64 bits to the given bUFFER */
#define INT64_TO_BUFFER(x, buf) \
do { \
(buf)[0] = (x) >> 56; \
(buf)[1] = (x) >> 48; \
(buf)[2] = (x) >> 40; \
(buf)[3] = (x) >> 32; \
(buf)[4] = (x) >> 24; \
(buf)[5] = (x) >> 16; \
(buf)[6] = (x) >> 8; \
(buf)[7] = (x); \
} while(0)
/* Convert an array of char containing vALUE to x */
#define BUFFER_TO_INT32(buf, x) \
do { \
x = ((buf)[0] << 24) | \
((buf)[1] << 16) | \
((buf)[2] << 8) | \
((buf)[3]); \
} while(0)
/* Convert an integer on 32 bits to an octet string from aSN1c tool */
#define INT32_TO_OCTET_STRING(x, aSN) \
do { \
(aSN)->buf = calloc(4, sizeof(uint8_t)); \
INT32_TO_BUFFER(x, ((aSN)->buf)); \
(aSN)->size = 4; \
} while(0)
#define INT32_TO_BIT_STRING(x, aSN) \
do { \
INT32_TO_OCTET_STRING(x, aSN); \
(aSN)->bits_unused = 0; \
} while(0)
#define INT16_TO_OCTET_STRING(x, aSN) \
do { \
(aSN)->buf = calloc(2, sizeof(uint8_t)); \
(aSN)->size = 2; \
INT16_TO_BUFFER(x, (aSN)->buf); \
} while(0)
#define INT8_TO_OCTET_STRING(x, aSN) \
do { \
(aSN)->buf = calloc(1, sizeof(uint8_t)); \
(aSN)->size = 1; \
INT8_TO_BUFFER(x, (aSN)->buf); \
} while(0)
#define MME_CODE_TO_OCTET_STRING INT8_TO_OCTET_STRING
#define M_TMSI_TO_OCTET_STRING INT32_TO_OCTET_STRING
#define MME_GID_TO_OCTET_STRING INT16_TO_OCTET_STRING
#define OCTET_STRING_TO_INT8(aSN, x) \
do { \
DevCheck((aSN)->size == 1, (aSN)->size, 0, 0); \
BUFFER_TO_INT8((aSN)->buf, x); \
} while(0)
#define OCTET_STRING_TO_INT16(aSN, x) \
do { \
DevCheck((aSN)->size == 2, (aSN)->size, 0, 0); \
BUFFER_TO_INT16((aSN)->buf, x); \
} while(0)
#define OCTET_STRING_TO_INT32(aSN, x) \
do { \
DevCheck((aSN)->size == 4, (aSN)->size, 0, 0); \
BUFFER_TO_INT32((aSN)->buf, x); \
} while(0)
#define BIT_STRING_TO_INT32(aSN, x) \
do { \
DevCheck((aSN)->bits_unused == 0, (aSN)->bits_unused, 0, 0); \
OCTET_STRING_TO_INT32(aSN, x); \
} while(0)
#define BIT_STRING_TO_CELL_IDENTITY(aSN, vALUE) \
do { \
DevCheck((aSN)->bits_unused == 4, (aSN)->bits_unused, 4, 0); \
vALUE.enb_id = ((aSN)->buf[0] << 12) | ((aSN)->buf[1] << 4) | \
((aSN)->buf[2] >> 4); \
vALUE.cell_id = ((aSN)->buf[2] << 4) | ((aSN)->buf[3] >> 4); \
} while(0)
#define MCC_HUNDREDS(vALUE) \
((vALUE) / 100)
/* When MNC is only composed of 2 digits, set the hundreds unit to 0xf */
#define MNC_HUNDREDS(vALUE, mNCdIGITlENGTH) \
( mNCdIGITlENGTH == 2 ? 15 : (vALUE) / 100)
#define MCC_MNC_DECIMAL(vALUE) \
(((vALUE) / 10) % 10)
#define MCC_MNC_DIGIT(vALUE) \
((vALUE) % 10)
#define MCC_TO_BUFFER(mCC, bUFFER) \
do { \
DevAssert(bUFFER != NULL); \
(bUFFER)[0] = MCC_HUNDREDS(mCC); \
(bUFFER)[1] = MCC_MNC_DECIMAL(mCC); \
(bUFFER)[2] = MCC_MNC_DIGIT(mCC); \
} while(0)
#define MCC_MNC_TO_PLMNID(mCC, mNC, mNCdIGITlENGTH, oCTETsTRING) \
do { \
(oCTETsTRING)->buf = calloc(3, sizeof(uint8_t)); \
(oCTETsTRING)->buf[0] = (MCC_MNC_DECIMAL(mCC) << 4) | MCC_HUNDREDS(mCC); \
(oCTETsTRING)->buf[1] = (MNC_HUNDREDS(mNC,mNCdIGITlENGTH) << 4) | MCC_MNC_DIGIT(mCC); \
(oCTETsTRING)->buf[2] = (MCC_MNC_DIGIT(mNC) << 4) | MCC_MNC_DECIMAL(mNC); \
(oCTETsTRING)->size = 3; \
} while(0)
#define MCC_MNC_TO_TBCD(mCC, mNC, mNCdIGITlENGTH, tBCDsTRING) \
do { \
char _buf[3]; \
DevAssert((mNCdIGITlENGTH == 3) || (mNCdIGITlENGTH == 2)); \
_buf[0] = (MCC_MNC_DECIMAL(mCC) << 4) | MCC_HUNDREDS(mCC); \
_buf[1] = (MNC_HUNDREDS(mNC,mNCdIGITlENGTH) << 4) | MCC_MNC_DIGIT(mCC);\
_buf[2] = (MCC_MNC_DIGIT(mNC) << 4) | MCC_MNC_DECIMAL(mNC); \
OCTET_STRING_fromBuf(tBCDsTRING, _buf, 3); \
} while(0)
#define TBCD_TO_MCC_MNC(tBCDsTRING, mCC, mNC, mNCdIGITlENGTH) \
do { \
int mNC_hundred; \
DevAssert((tBCDsTRING)->size == 3); \
mNC_hundred = (((tBCDsTRING)->buf[1] & 0xf0) >> 4); \
if (mNC_hundred == 0xf) { \
mNC_hundred = 0; \
mNCdIGITlENGTH = 2; \
} else { \
mNCdIGITlENGTH = 3; \
} \
mCC = (((((tBCDsTRING)->buf[0]) & 0xf0) >> 4) * 10) + \
((((tBCDsTRING)->buf[0]) & 0x0f) * 100) + \
(((tBCDsTRING)->buf[1]) & 0x0f); \
mNC = (mNC_hundred * 100) + \
((((tBCDsTRING)->buf[2]) & 0xf0) >> 4) + \
((((tBCDsTRING)->buf[2]) & 0x0f) * 10); \
} while(0)
#define TBCD_TO_PLMN_T(tBCDsTRING, pLMN) \
do { \
DevAssert((tBCDsTRING)->size == 3); \
(pLMN)->mcc_digit2 = (((tBCDsTRING)->buf[0] & 0xf0) >> 4); \
(pLMN)->mcc_digit1 = ((tBCDsTRING)->buf[0] & 0x0f); \
(pLMN)->mnc_digit3 = (((tBCDsTRING)->buf[1] & 0xf0) >> 4); \
(pLMN)->mcc_digit3 = ((tBCDsTRING)->buf[1] & 0x0f); \
(pLMN)->mnc_digit2 = (((tBCDsTRING)->buf[2] & 0xf0) >> 4); \
(pLMN)->mnc_digit1 = ((tBCDsTRING)->buf[2] & 0x0f); \
} while(0)
#define PLMN_T_TO_TBCD(pLMN, tBCDsTRING, mNClENGTH) \
do { \
tBCDsTRING[0] = (pLMN.mcc_digit2 << 4) | pLMN.mcc_digit1; \
/* ambiguous (think about len 2) */ \
if (mNClENGTH == 2) { \
tBCDsTRING[1] = (0x0F << 4) | pLMN.mcc_digit3; \
tBCDsTRING[2] = (pLMN.mnc_digit2 << 4) | pLMN.mnc_digit1; \
} else { \
tBCDsTRING[1] = (pLMN.mnc_digit3 << 4) | pLMN.mcc_digit3; \
tBCDsTRING[2] = (pLMN.mnc_digit2 << 4) | pLMN.mnc_digit1; \
} \
} while(0)
#define PLMN_T_TO_MCC_MNC(pLMN, mCC, mNC, mNCdIGITlENGTH) \
do { \
mCC = pLMN.mcc_digit3 * 100 + pLMN.mcc_digit2 * 10 + pLMN.mcc_digit1; \
mNCdIGITlENGTH = (pLMN.mnc_digit3 == 0xF ? 2 : 3); \
mNC = (mNCdIGITlENGTH == 2 ? 0 : pLMN.mnc_digit3 * 100) \
+ pLMN.mnc_digit2 * 10 + pLMN.mnc_digit1; \
} while(0)
/*
* TS 36.413 v10.9.0 section 9.2.1.37:
* Macro eNB ID:
* Equal to the 20 leftmost bits of the Cell
* Identity IE contained in the E-UTRAN CGI
* IE (see subclause 9.2.1.38) of each cell
* served by the eNB.
*/
#define MACRO_ENB_ID_TO_BIT_STRING(mACRO, bITsTRING) \
do { \
(bITsTRING)->buf = calloc(3, sizeof(uint8_t)); \
(bITsTRING)->buf[0] = ((mACRO) >> 12); \
(bITsTRING)->buf[1] = (mACRO) >> 4; \
(bITsTRING)->buf[2] = ((mACRO) & 0x0f) << 4; \
(bITsTRING)->size = 3; \
(bITsTRING)->bits_unused = 4; \
} while(0)
/*
* TS 36.413 v10.9.0 section 9.2.1.38:
* E-UTRAN CGI/Cell Identity
* The leftmost bits of the Cell
* Identity correspond to the eNB
* ID (defined in subclause 9.2.1.37).
*/
#define MACRO_ENB_ID_TO_CELL_IDENTITY(mACRO, cELL_iD, bITsTRING) \
do { \
(bITsTRING)->buf = calloc(4, sizeof(uint8_t)); \
(bITsTRING)->buf[0] = ((mACRO) >> 12); \
(bITsTRING)->buf[1] = (mACRO) >> 4; \
(bITsTRING)->buf[2] = (((mACRO) & 0x0f) << 4) | ((cELL_iD) >> 4); \
(bITsTRING)->buf[3] = ((cELL_iD) & 0x0f) << 4; \
(bITsTRING)->size = 4; \
(bITsTRING)->bits_unused = 4; \
} while(0)
/* 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]
#define TAC_TO_ASN1 INT16_TO_OCTET_STRING
#define GTP_TEID_TO_ASN1 INT32_TO_OCTET_STRING
#define OCTET_STRING_TO_TAC OCTET_STRING_TO_INT16
#define OCTET_STRING_TO_MME_CODE OCTET_STRING_TO_INT8
#define OCTET_STRING_TO_M_TMSI OCTET_STRING_TO_INT32
#define OCTET_STRING_TO_MME_GID OCTET_STRING_TO_INT16
#define OCTET_STRING_TO_CSG_ID OCTET_STRING_TO_INT27
/* Convert the IMSI contained by a char string NULL terminated to uint64_t */
#define IMSI_STRING_TO_IMSI64(sTRING, iMSI64_pTr) sscanf(sTRING, IMSI_64_FMT, iMSI64_pTr)
#define IMSI64_TO_STRING(iMSI64, sTRING) snprintf(sTRING, IMSI_BCD_DIGITS_MAX+1, IMSI_64_FMT, iMSI64)
imsi64_t imsi_to_imsi64(oai::cn::core::imsi_t * const imsi);
#define IMSI_TO_STRING(iMsI_t_PtR,iMsI_sTr, MaXlEn) \
do { \
int l_i = 0; \
int l_j = 0; \
while((l_i < IMSI_BCD8_SIZE) && (l_j < MaXlEn - 1)){ \
if((((iMsI_t_PtR)->u.value[l_i] & 0xf0) >> 4) > 9) \
break; \
sprintf(((iMsI_sTr) + l_j), "%u",(((iMsI_t_PtR)->u.value[l_i] & 0xf0) >> 4)); \
l_j++; \
if(((iMsI_t_PtR)->u.value[l_i] & 0xf) > 9 || (l_j >= MaXlEn - 1)) \
break; \
sprintf(((iMsI_sTr) + l_j), "%u", ((iMsI_t_PtR)->u.value[l_i] & 0xf)); \
l_j++; \
l_i++; \
} \
for(; l_j < MaXlEn; l_j++) \
(iMsI_sTr)[l_j] = '\0'; \
} while (0);\
#define IMEI_TO_STRING(iMeI_t_PtR,iMeI_sTr, MaXlEn) \
{\
int l_offset = 0;\
int l_ret = 0;\
l_ret = snprintf(iMeI_sTr + l_offset, MaXlEn - l_offset, "%u%u%u%u%u%u%u%u",\
(iMeI_t_PtR)->u.num.tac1, (iMeI_t_PtR)->u.num.tac2,\
(iMeI_t_PtR)->u.num.tac3, (iMeI_t_PtR)->u.num.tac4,\
(iMeI_t_PtR)->u.num.tac5, (iMeI_t_PtR)->u.num.tac6,\
(iMeI_t_PtR)->u.num.tac7, (iMeI_t_PtR)->u.num.tac8);\
if (l_ret > 0) {\
l_offset += l_ret;\
l_ret = snprintf(iMeI_sTr + l_offset, MaXlEn - l_offset, "%u%u%u%u%u%u",\
(iMeI_t_PtR)->u.num.snr1, (iMeI_t_PtR)->u.num.snr2,\
(iMeI_t_PtR)->u.num.snr3, (iMeI_t_PtR)->u.num.snr4,\
(iMeI_t_PtR)->u.num.snr5, (iMeI_t_PtR)->u.num.snr6);\
}\
if (((iMeI_t_PtR)->u.num.parity != 0x0) && (l_ret > 0)) {\
l_offset += l_ret;\
l_ret = snprintf(iMeI_sTr + l_offset, MaXlEn - l_offset, "%u", (iMeI_t_PtR)->u.num.cdsd);\
}\
}
void hexa_to_ascii(uint8_t *from, char *to, size_t length);
int ascii_to_hex(uint8_t *dst, const char *h);
#define UINT8_TO_BINARY_FMT "%c%c%c%c%c%c%c%c"
#define UINT8_TO_BINARY_ARG(bYtE) \
((bYtE) & 0x80 ? '1':'0'),\
((bYtE) & 0x40 ? '1':'0'),\
((bYtE) & 0x20 ? '1':'0'),\
((bYtE) & 0x10 ? '1':'0'),\
((bYtE) & 0x08 ? '1':'0'),\
((bYtE) & 0x04 ? '1':'0'),\
((bYtE) & 0x02 ? '1':'0'),\
((bYtE) & 0x01 ? '1':'0')
#define FTEID_T_2_IP_ADDRESS_T(fte_p,ip_p) \
do { \
(ip_p)->ipv4 = false; \
(ip_p)->ipv6 = false; \
if ((fte_p)->ipv4) { \
(ip_p)->ipv4 = true; \
(ip_p)->address.ipv4_address.s_addr = (fte_p)->ipv4_address.s_addr; \
} \
else if ((fte_p)->ipv6) { \
(ip_p)->ipv6 = true; \
memcpy(&(ip_p)->address.ipv6_address, &(fte_p)->ipv6_address, sizeof((fte_p)->ipv6_address)); \
} \
} while (0)
#ifdef __cplusplus
}
#endif
void paa_to_pfcp_ue_ip_address(const oai::cn::core::paa_t& paa, oai::cn::core::pfcp::ue_ip_address_t& ue_ip_address);
void pdn_ip_to_pfcp_ue_ip_address(const oai::cn::core::pdn_type_t& pdn_type,
const struct in_addr& ipv4_address,
const struct in6_addr ipv6_address,
oai::cn::core::pfcp::ue_ip_address_t& ue_ip_address);
#endif /* FILE_CONVERSIONS_HPP_SEEN */
/*
* Copyright (c) 2017 Sprint
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#include <stdlib.h>
#include <iostream>
#include "epc.h"
using namespace EPC;
std::string Utility::home_network( const char *mnc, const char *mcc )
{
std::string s;
// '^mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::home_network( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return home_network( mnc, mcc );
}
std::string Utility::home_network_gprs( const char *mnc, const char *mcc )
{
std::string s;
// '^mnc(\d{3})\.mcc(\d{3})\.gprs'
s.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.append( "gprs" );
return s;
}
std::string Utility::home_network_gprs( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return home_network_gprs( mnc, mcc );
}
std::string Utility::tai_fqdn( const char *lb, const char *hb, const char *mnc, const char *mcc )
{
std::string s;
// '^tac-lb([0-9a-fA-F]{2})\.tac-hb([0-9a-fA-F]{2})\.tac\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "tac-lb" )
.append( lb )
.append( ".tac-hb" )
.append( hb )
.append( ".tac.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::tai_fqdn( const char *lb, const char *hb, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return tai_fqdn( lb, hb, mnc, mcc );
}
std::string Utility::mme_fqdn( const char *mmec, const char *mmegi, const char *mnc, const char *mcc )
{
std::string s;
// '^mmec([0-9a-fA-F]{2})\.mmegi([0-9a-fA-F]{4})\.mme.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "mmec" )
.append( mmec )
.append( ".mmegi" )
.append( mmegi )
.append( ".mme.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::mme_fqdn( const char *mmec, const char *mmegi, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return mme_fqdn( mmec, mmegi, mnc, mcc );
}
std::string Utility::mme_pool_fqdn( const char *mmegi, const char *mnc, const char *mcc )
{
std::string s;
// '^mmegi([0-9a-fA-F]{4})\.mme\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "mmegi" )
.append( mmegi )
.append( ".mme.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::mme_pool_fqdn( const char *mmegi, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return mme_pool_fqdn( mmegi, mnc, mcc );
}
std::string Utility::rai_fqdn( const char *rac, const char *lac, const char *mnc, const char *mcc )
{
std::string s;
// '^rac([0-9a-fA-F]{4})\.lac([0-9a-fA-F]{4})\.rac\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "rac" )
.append( rac )
.append( ".lac" )
.append( lac )
.append( ".rac.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::rai_fqdn( const char *rac, const char *lac, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return rai_fqdn( rac, lac, mnc, mcc );
}
std::string Utility::rnc_fqdn( const char *rnc, const char *mnc, const char *mcc )
{
std::string s;
// '^rnc([0-9a-fA-F]{4})\.rnc\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "rnc" )
.append( rnc )
.append( ".rnc.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::rnc_fqdn( const char *rnc, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return rnc_fqdn( rnc, mnc, mcc );
}
std::string Utility::sgsn_fqdn( const char *nri, const char *rac, const char *lac, const char *mnc, const char *mcc )
{
std::string s;
// '^nri([0-9a-fA-F]{4})\.rac([0-9a-fA-F]{4})\.lac([0-9a-fA-F]{4})\.rac\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "nri" )
.append( nri )
.append( ".rac" )
.append( rac )
.append( ".lac" )
.append( lac )
.append( ".rac.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::sgsn_fqdn( const char *nri, const char *rac, const char *lac, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return sgsn_fqdn( nri, rac, lac, mnc, mcc );
}
std::string Utility::epc_nodes_domain_fqdn( const char *mnc, const char *mcc )
{
std::string s;
// '^node\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "node.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::epc_nodes_domain_fqdn( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return epc_nodes_domain_fqdn( mnc, mcc );
}
std::string Utility::epc_node_fqdn( const char *node, const char *mnc, const char *mcc )
{
std::string s;
// '^(.+)\.node\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org$'
s.append( node )
.append( ".node.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::epc_node_fqdn( const char *node, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return epc_node_fqdn( node, mnc, mcc );
}
std::string Utility::nonemergency_epdg_oi_fqdn( const char *mnc, const char *mcc )
{
std::string s;
// '^epdg\.epc\.mnc(\d{3})\.mcc(\d{3})\.pub\.3gppnetworks\.org'
s.append( "epdg.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.append( "pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::nonemergency_epdg_oi_fqdn( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return nonemergency_epdg_oi_fqdn( mnc, mcc );
}
std::string Utility::nonemergency_epdg_tai_fqdn( const char *lb, const char *hb, const char *mnc, const char *mcc )
{
std::string s;
// '^tac-lb([0-9a-fA-F]{2})\.tac-hb([0-9a-fA-F]{2})\.tac\.epdg\.epc\.mnc(\d{3})\.mcc(\d{3})\.pub\.3gppnetworks\.org'
s.append( "tac-lb" )
.append( lb )
.append( ".tac-hb" )
.append( hb )
.append( ".tac.epdg.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::nonemergency_epdg_tai_fqdn( const char *lb, const char *hb, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return nonemergency_epdg_tai_fqdn( lb, hb, mnc, mcc );
}
std::string Utility::nonemergency_epdg_lac_fqdn( const char *lac, const char *mnc, const char *mcc )
{
std::string s;
// '^lac([0-9a-fA-F]{4})\.epdg\.epc\.mnc(\d{3})\.mcc(\d{3})\.pub\.3gppnetworks\.org'
s.append( "lac" )
.append( lac )
.append( ".epdg.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.append( "pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::nonemergency_epdg_lac_fqdn( const char *lac, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return nonemergency_epdg_lac_fqdn( lac, mnc, mcc );
}
std::string Utility::nonemergency_epdg_visitedcountry_fqdn( const char *mcc )
{
std::string s;
// '^epdg\.epc\.mcc(\d{3})\.visited-country\.pub\.3gppnetworks\.org'
s.append( "epdg.epc." )
.APPEND_MCC( mcc )
.append( "visited-country.pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::nonemergency_epdg_visitedcountry_fqdn( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return nonemergency_epdg_visitedcountry_fqdn( mcc );
}
std::string Utility::emergency_epdg_oi_fqdn( const char *mnc, const char *mcc )
{
std::string s;
// '^sos\.epdg\.epc\.mnc(\d{3})\.mcc(\d{3})\.pub\.3gppnetworks\.org'
s.append( "sos.epdg.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.append( "pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::emergency_epdg_oi_fqdn( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return emergency_epdg_oi_fqdn( mnc, mcc );
}
std::string Utility::emergency_epdg_tai_fqdn( const char *lb, const char *hb, const char *mnc, const char *mcc )
{
std::string s;
// '^tac-lb([0-9a-fA-F]{2})\.tac-hb([0-9a-fA-F]{2})\.tac\.sos\.epdg\.epc\.mnc(\d{3})\.mcc(\d{3})\.pub\.3gppnetworks\.org',
s.append( "tac-lb" )
.append( lb )
.append( ".tac-hb" )
.append( hb )
.append( ".tac.sos.epdg.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.append( "pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::emergency_epdg_tai_fqdn( const char *lb, const char *hb, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return emergency_epdg_tai_fqdn( lb, hb, mnc, mcc );
}
std::string Utility::emergency_epdg_lac_fqdn( const char *lac, const char *mnc, const char *mcc )
{
std::string s;
// '^lac([0-9a-fA-F]{4})\.sos\.epdg\.epc\.mnc(\d{3})\.mcc(\d{3})\.pub\.3gppnetworks\.org'
s.append( "lac" )
.append( lac )
.append( ".sos.epdg.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.append( "pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::emergency_epdg_lac_fqdn( const char *lac, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return emergency_epdg_lac_fqdn( lac, mnc, mcc );
}
std::string Utility::emergency_epdg_visitedcountry_fqdn( const char *mcc )
{
std::string s;
// '^sos\.epdg\.epc\.mcc(\d{3})\.visited-country\.pub\.3gppnetworks\.org'
s.append( "sos.epdg.epc." )
.APPEND_MCC( mcc )
.append( "visited-country.pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::emergency_epdg_visitedcountry_fqdn( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return emergency_epdg_visitedcountry_fqdn( mcc );
}
std::string Utility::global_enodeb_id_fqdn( const char *enb, const char *mcc )
{
std::string s;
// '^enb([0-9a-fA-F]{4})\.enb\.epc\.mcc(\d{3})\.visited-country\.pub\.3gppnetworks\.org'
s.append( "enb" )
.append( enb )
.append( ".enb.epc." )
.APPEND_MCC( mcc )
.append( "visited-country.pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::global_enodeb_id_fqdn( const char *enb, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return global_enodeb_id_fqdn( enb, mcc );
}
std::string Utility::local_homenetwork_fqdn( const char *lhn, const char *mcc )
{
std::string s;
// '^lhn(.+)\.lhn\.epc\.mcc(\d{3})\.visited-country\.pub\.3gppnetworks\.org$'
s.append( "lhn" )
.append( lhn )
.append( ".lhn.epc." )
.APPEND_MCC( mcc )
.append( "visited-country.pub." )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::local_homenetwork_fqdn( const char *lhn, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return local_homenetwork_fqdn( lhn, mcc );
}
std::string Utility::epc( const char *mnc, const char *mcc )
{
std::string s;
// '^epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org'
s.append( "epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::epc( const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return epc( mnc, mcc );
}
std::string Utility::apn_fqdn( const char *apnoi, const char *mnc, const char *mcc )
{
std::string s;
// '(.+)\.apn\.epc\.mnc(\d{3})\.mcc(\d{3})\.3gppnetworks\.org$'
s.append( apnoi )
.append( ".apn.epc." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.APPEND_3GPPNETWORK;
return s;
}
std::string Utility::apn_fqdn( const char *apnoi, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return apn_fqdn( apnoi, mnc, mcc );
}
std::string Utility::apn( const char *apnoi, const char *mnc, const char *mcc )
{
std::string s;
// '(.+)\.apn\.mnc(\d{3})\.mcc(\d{3})\.gprs$'}
s.append( apnoi )
.append( ".apn." )
.APPEND_MNC( mnc )
.APPEND_MCC( mcc )
.append( "gprs" );
return s;
}
std::string Utility::apn( const char *apnoi, const unsigned char *plmnid )
{
PARSE_PLMNID( plmnid );
return apn( apnoi, mnc, mcc );
}
std::string Utility::apn_label(const std::string& apn)
{
std::string apn_label = {};
bool to_count = true;
uint8_t counted = 0;
int index = 0;
apn_label.push_back('?');
for (int i = 0; i < apn.length(); ++i) {
if (isalnum(apn[i]) || (apn[i] == '-')) {
apn_label.push_back(apn[i]);
counted++;
} else if (apn[i] == '.') {
apn_label.push_back('?');
if (to_count) { // always true
apn_label[index] = counted;
}
to_count = true;
counted = 0;
index = apn_label.length() - 1;
}
}
if (to_count) {
apn_label[index] = counted;
}
return apn_label;
}
/*
* Copyright (c) 2017 Sprint
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#ifndef __EPC_H
#define __EPC_H
#include <stdio.h>
#include <algorithm>
#include <string>
#include <sstream>
#include <list>
#include <vector>
/*
MCC digit 1 - low order nibble octet 1
MCC digit 2 - high order nibble octet 1
MCC digit 3 - low order nibble octet 2
MCC = [MCC digit 1][MCC digit 2][MCC digit 3]
MNC digit 1 - low order nibble octet 3
MNC digit 2 - high order nibble octet 3
MNC digit 3 - high order nibble octet 2, nibble set to 1111 if MNC len is 2
MNC = [MNC digit 1][MNC digit 2][MNC digit 3]
*/
#define LOW_NIBBLE(a) (((unsigned char)a) & 0x0f)
#define HIGH_NIBBLE(a) ((((unsigned char)a) & 0xf0) >> 4)
#define PARSE_MNC(a,b) { \
if ( HIGH_NIBBLE(b[1]) == 0x0f ) { \
a[0] = '0'; \
a[1] = LOW_NIBBLE(b[2]) + '0'; \
a[2] = HIGH_NIBBLE(b[2]) + '0'; \
a[3] = '\0'; \
} else { \
a[0] = LOW_NIBBLE(b[2]) + '0'; \
a[1] = HIGH_NIBBLE(b[2]) + '0'; \
a[2] = HIGH_NIBBLE(b[1]) + '0'; \
a[3] = '\0'; \
} \
}
#define PARSE_MCC(a,b) { \
a[0] = LOW_NIBBLE(b[0]) + '0'; \
a[1] = HIGH_NIBBLE(b[0]) + '0'; \
a[2] = LOW_NIBBLE(b[1]) + '0'; \
a[3] = '\0'; \
}
#define PARSE_PLMNID(a) \
char mnc[4], mcc[4]; \
PARSE_MNC(mnc,a); \
PARSE_MCC(mcc,a);
#define APPEND_MNC(a) append("mnc").append(a).append(".")
#define APPEND_MCC(a) append("mcc").append(a).append(".")
#define APPEND_3GPPNETWORK append("3gppnetwork.org")
namespace EPC
{
enum AppServiceEnum
{
x_3gpp_unknown,
x_3gpp_pgw,
x_3gpp_sgw,
x_3gpp_ggsn,
x_3gpp_sgsn,
x_3gpp_mme,
x_3gpp_msc
};
enum AppProtocolEnum
{
x_unknown,
x_gn,
x_gp,
x_nq,
x_nqprime,
x_s10,
x_s11,
x_s12,
x_s1_mme,
x_s1_u,
x_s16,
x_s2a_gtp,
x_s2a_mipv4,
x_s2a_pmip,
x_s2b_gtp,
x_s2b_pmip,
x_s2c_dsmip,
x_s3,
x_s4,
x_s5_gtp,
x_s5_pmip,
x_s6a,
x_s8_gtp,
x_s8_pmip,
x_sv
};
enum PGWAppProtocolEnum
{
pgw_x_gn,
pgw_x_gp,
pgw_x_s2a_gtp,
pgw_x_s2a_mipv4,
pgw_x_s2a_pmip,
pgw_x_s2b_gtp,
pgw_x_s2b_pmip,
pgw_x_s2c_dsmip,
pgw_x_s5_gtp,
pgw_x_s5_pmip,
pgw_x_s8_gtp,
pgw_x_s8_pmip
};
enum SGWAppProtocolEnum
{
sgw_x_s11,
sgw_x_s12,
sgw_x_s1_u,
sgw_x_s2a_pmip,
sgw_x_s2b_pmip,
sgw_x_s4,
sgw_x_s5_gtp,
sgw_x_s5_pmip,
sgw_x_s8_gtp,
sgw_x_s8_pmip
};
enum GGSNAppProtocolEnum
{
ggsn_x_gn,
ggsn_x_gp
};
enum SGSNAppProtocolEnum
{
sgsn_x_gn,
sgsn_x_gp,
sgsn_x_nqprime,
sgsn_x_s16,
sgsn_x_s3,
sgsn_x_s4,
sgsn_x_sv
};
enum MMEAppProtocolEnum
{
mme_x_gn,
mme_x_gp,
mme_x_nq,
mme_x_s10,
mme_x_s11,
mme_x_s1_mme,
mme_x_s3,
mme_x_s6a,
mme_x_sv
};
enum MSCAppProtocolEnum
{
msc_x_sv
};
enum DiameterApplicationEnum
{
dia_app_unknown,
/*
+------------------+----------------------------+
| Tag | Diameter Application |
+------------------+----------------------------+
| aaa+ap1 | NASREQ [RFC3588] |
| aaa+ap2 | Mobile IPv4 [RFC4004] |
| aaa+ap3 | Base Accounting [RFC3588] |
| aaa+ap4 | Credit Control [RFC4006] |
| aaa+ap5 | EAP [RFC4072] |
| aaa+ap6 | SIP [RFC4740] |
| aaa+ap7 | Mobile IPv6 IKE [RFC5778] |
| aaa+ap8 | Mobile IPv6 Auth [RFC5778] |
| aaa+ap9 | QoS [RFC5866] |
| aaa+ap4294967295 | Relay [RFC3588] |
+------------------+----------------------------+
*/
dia_app_nasreq,
dia_app_mobile_ipv4,
dia_app_base_accounting,
dia_app_credit_control,
dia_app_eap,
dia_app_sip6,
dia_app_mobile_ipv6_ike,
dia_app_mobile_ipv6_auth,
dia_app_qos,
dia_app_relay,
/*
+----------------+----------------------+
| Tag | Diameter Application |
+----------------+----------------------+
| aaa+ap16777250 | 3GPP STa [TS29.273] |
| aaa+ap16777251 | 3GPP S6a [TS29.272] |
| aaa+ap16777264 | 3GPP SWm [TS29.273] |
| aaa+ap16777267 | 3GPP S9 [TS29.215] |
+----------------+----------------------+
*/
dia_app_3gpp_sta,
dia_app_3gpp_s6a,
dia_app_3gpp_swm,
dia_app_3gpp_s9,
/*
+----------------+--------------------------------------------------+
| Tag | Diameter Application |
+----------------+--------------------------------------------------+
| aaa+ap16777281 | WiMAX Network Access Authentication and |
| | Authorization Diameter Application (WNAAADA) |
| | [WiMAX-BASE] |
| aaa+ap16777282 | WiMAX Network Accounting Diameter Application |
| | (WNADA) [WiMAX-BASE] |
| aaa+ap16777283 | WiMAX MIP4 Diameter Application (WM4DA) |
| | [WiMAX-BASE] |
| aaa+ap16777284 | WiMAX MIP6 Diameter Application (WM6DA) |
| | [WiMAX-BASE] |
| aaa+ap16777285 | WiMAX DHCP Diameter Application (WDDA) |
| | [WiMAX-BASE] |
| aaa+ap16777286 | WiMAX Location Authentication Authorization |
| | Diameter Application (WLAADA) [WiMAX-LBS] |
| aaa+ap16777287 | WiMAX Policy and Charging Control R3 Policies |
| | Diameter Application (WiMAX PCC-R3-P) |
| | [WiMAX-PCC] |
| aaa+ap16777288 | WiMAX Policy and Charging Control R3 Offline |
| | Charging Diameter Application (WiMAX PCC-R3-OFC) |
| | [WiMAX-PCC] |
| aaa+ap16777289 | WiMAX Policy and Charging Control R3 Offline |
| | Charging Prime Diameter Application (WiMAX |
| | PCC-R3-OFC-PRIME) [WiMAX-PCC] |
| aaa+ap16777290 | WiMAX Policy and Charging Control R3 Online |
| | Charging Diameter Application (WiMAX PCC-R3-OC) |
| | [WiMAX-PCC] |
+----------------+--------------------------------------------------+
*/
dia_app_wimax_wnaaada,
dia_app_wimax_wnada,
dia_app_wimax_wm4da,
dia_app_wimax_wm6da,
dia_app_wimax_wdda,
dia_app_wimax_wlaada,
dia_app_wimax_pcc_r3_p,
dia_app_wimax_pcc_r3_ofc,
dia_app_wimax_pcc_r3_ofc_prime,
dia_app_wimax_pcc_r3_oc
};
enum DiameterProtocolEnum
{
dia_protocol_unknown,
dia_protocol_tcp,
dia_protocol_sctp,
dia_protocol_tls_tcp
};
class Utility
{
public:
static std::string home_network( const char *mnc, const char *mcc );
static std::string home_network( const unsigned char *plmnid );
static std::string home_network_gprs( const char *mnc, const char *mcc );
static std::string home_network_gprs( const unsigned char *plmnid );
static std::string tai_fqdn( const char *lb, const char *hb, const char *mnc, const char *mcc );
static std::string tai_fqdn( const char *lb, const char *hb, const unsigned char *plmnid );
static std::string mme_fqdn( const char *mmec, const char *mmegi, const char *mnc, const char *mcc );
static std::string mme_fqdn( const char *mmec, const char *mmegi, const unsigned char *plmnid );
static std::string mme_pool_fqdn( const char *mmegi, const char *mnc, const char *mcc );
static std::string mme_pool_fqdn( const char *mmegi, const unsigned char *plmnid );
static std::string rai_fqdn( const char *rac, const char *lac, const char *mnc, const char *mcc );
static std::string rai_fqdn( const char *rac, const char *lac, const unsigned char *plmnid );
static std::string rnc_fqdn( const char *rnc, const char *mnc, const char *mcc );
static std::string rnc_fqdn( const char *rnc, const unsigned char *plmnid );
static std::string sgsn_fqdn( const char *nri, const char *rac, const char *lac, const char *mnc, const char *mcc );
static std::string sgsn_fqdn( const char *nri, const char *rac, const char *lac, const unsigned char *plmnid );
static std::string epc_nodes_domain_fqdn( const char *mnc, const char *mcc );
static std::string epc_nodes_domain_fqdn( const unsigned char *plmnid );
static std::string epc_node_fqdn( const char *node, const char *mnc, const char *mcc );
static std::string epc_node_fqdn( const char *node, const unsigned char *plmnid );
static std::string nonemergency_epdg_oi_fqdn( const char *mnc, const char *mcc );
static std::string nonemergency_epdg_oi_fqdn( const unsigned char *plmnid );
static std::string nonemergency_epdg_tai_fqdn( const char *lb, const char *hb, const char *mnc, const char *mcc );
static std::string nonemergency_epdg_tai_fqdn( const char *lb, const char *hb, const unsigned char *plmnid );
static std::string nonemergency_epdg_lac_fqdn( const char *lac, const char *mnc, const char *mcc );
static std::string nonemergency_epdg_lac_fqdn( const char *lac, const unsigned char *plmnid );
static std::string nonemergency_epdg_visitedcountry_fqdn( const char *mcc );
static std::string nonemergency_epdg_visitedcountry_fqdn( const unsigned char *plmnid );
static std::string emergency_epdg_oi_fqdn( const char *mnc, const char *mcc );
static std::string emergency_epdg_oi_fqdn( const unsigned char *plmnid );
static std::string emergency_epdg_tai_fqdn( const char *lb, const char *hb, const char *mnc, const char *mcc );
static std::string emergency_epdg_tai_fqdn( const char *lb, const char *hb, const unsigned char *plmnid );
static std::string emergency_epdg_lac_fqdn( const char *lac, const char *mnc, const char *mcc );
static std::string emergency_epdg_lac_fqdn( const char *lac, const unsigned char *plmnid );
static std::string emergency_epdg_visitedcountry_fqdn( const char *mcc );
static std::string emergency_epdg_visitedcountry_fqdn( const unsigned char *plmnid );
static std::string global_enodeb_id_fqdn( const char *enb, const char *mcc );
static std::string global_enodeb_id_fqdn( const char *enb, const unsigned char *plmnid );
static std::string local_homenetwork_fqdn( const char *lhn, const char *mcc );
static std::string local_homenetwork_fqdn( const char *lhn, const unsigned char *plmnid );
static std::string epc( const char *mnc, const char *mcc );
static std::string epc( const unsigned char *plmnid );
static std::string apn_fqdn( const char *apnoi, const char *mnc, const char *mcc );
static std::string apn_fqdn( const char *apnoi, const unsigned char *plmnid );
static std::string apn( const char *apnoi, const char *mnc, const char *mcc );
static std::string apn( const char *apnoi, const unsigned char *plmnid );
static std::string apn_label(const std::string& apn);
static AppServiceEnum getAppService( const std::string &s );
static AppProtocolEnum getAppProtocol( const std::string &p );
static const char *getAppService( AppServiceEnum s );
static const char *getAppProtocol( AppProtocolEnum proto );
static AppProtocolEnum getAppProtocol( PGWAppProtocolEnum proto );
static AppProtocolEnum getAppProtocol( SGWAppProtocolEnum proto );
static AppProtocolEnum getAppProtocol( GGSNAppProtocolEnum proto );
static AppProtocolEnum getAppProtocol( SGSNAppProtocolEnum proto );
static AppProtocolEnum getAppProtocol( MMEAppProtocolEnum proto );
static AppProtocolEnum getAppProtocol( MSCAppProtocolEnum proto );
static std::string diameter_fqdn( const char *mnc, const char *mcc );
static std::string diameter_fqdn( const unsigned char *plmnid );
static uint32_t getDiameterApplication( DiameterApplicationEnum app );
static const char *getDiameterProtocol( DiameterProtocolEnum protocol );
static std::string getDiameterService( DiameterApplicationEnum app, DiameterProtocolEnum protocol );
private:
Utility() {}
};
} // namespace EPC
#endif // #ifndef __EPC_H
/*
* 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.h
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_EPC_CONVERSIONS_HPP_SEEN
#define FILE_EPC_CONVERSIONS_HPP_SEEN
#include "common_types.h"
#include "3gpp_23.003.h"
#include "3gpp_24.008.h"
#include "3gpp_29.274.h"
#include "EpsQualityOfService.h"
namespace oai {
namespace cn {
namespace util {
inline void build_fteid(core::fteid_t& fteid, const core::ip_address_t ip,const teid_t teid) {
fteid.teid = teid;
fteid.ipv4 = ip.ipv4;
fteid.ipv4_address = ip.address;
}
#define FTEID_T_2_IP_ADDRESS_T(fte_p,ip_p) \
do { \
(ip_p)->ipv4 = false; \
(ip_p)->ipv6 = false; \
if ((fte_p)->ipv4) { \
(ip_p)->ipv4 = true; \
(ip_p)->address.ipv4_address.s_addr = (fte_p)->ipv4_address.s_addr; \
} \
else if ((fte_p)->ipv6) { \
(ip_p)->ipv6 = true; \
memcpy(&(ip_p)->address.ipv6_address, &(fte_p)->ipv6_address, sizeof((fte_p)->ipv6_address)); \
} \
} while (0)
}
}
}
#endif /* FILE_CONVERSIONS_SEEN */
/* From https://gist.github.com/javiermon/6272065#file-gateway_netlink-c */
/*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <net/if.h>
#include <fstream> // std::ifstream
#include <string>
#include "common_defs.h"
#include "get_gateway_netlink.hpp"
#include "logger.hpp"
#define BUFFER_SIZE 4096
using namespace std;
//------------------------------------------------------------------------------
bool oai::cn::util::get_iface_l2_addr(const std::string& iface, std::string& mac)
{
std::string mac_address_path = fmt::format("/sys/class/net/{}/address", iface);
std::ifstream mac_address_in(mac_address_path.c_str(), ios_base::in | ios_base::binary );
char wb[32];
mac_address_in.get(wb, 32);
mac.assign(wb);
Logger::pfcp_switch().error("Found IFace %s MAC %s", iface.c_str(), mac.c_str());
mac.erase(std::remove(mac.begin(), mac.end(), ':'), mac.end());
return true;
// ifr = {};
// strncpy ((char *) ifr.ifr_name, ifname, IFNAMSIZ);
// if (ioctl(sd, SIOCGIFFLAGS, &ifr) == 0) {
// if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
// if (ioctl(sd, SIOCGIFHWADDR, &ifr) == 0) {
// memcpy(pdn_mac_address, ifr.ifr_hwaddr.sa_data, 6);
// }
// }
// }
}
//------------------------------------------------------------------------------
bool oai::cn::util::get_gateway_and_iface(std::string& gw, std::string& iface)
{
int received_bytes = 0, msg_len = 0, route_attribute_len = 0;
int sock = -1, msgseq = 0;
struct nlmsghdr *nlh, *nlmsg;
struct rtmsg *route_entry;
// This struct contain route attributes (route type)
struct rtattr *route_attribute;
char gateway_address[INET_ADDRSTRLEN], interface[IF_NAMESIZE+1];
char msgbuf[BUFFER_SIZE], buffer[BUFFER_SIZE];
char *ptr = buffer;
struct timeval tv;
int rv = RETURNok;
if ((sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
perror("socket failed");
return false;
}
memset(msgbuf, 0, sizeof(msgbuf));
memset(gateway_address, 0, sizeof(gateway_address));
memset(interface, 0, sizeof(interface));
memset(buffer, 0, sizeof(buffer));
/* point the header and the msg structure pointers into the buffer */
nlmsg = (struct nlmsghdr *)msgbuf;
/* Fill in the nlmsg header*/
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nlmsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlmsg->nlmsg_seq = msgseq++; // Sequence of the message packet.
nlmsg->nlmsg_pid = getpid(); // PID of process sending the request.
/* 1 Sec Timeout to avoid stall */
tv.tv_sec = 1;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
/* send msg */
if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) {
perror("send failed");
return false;
}
/* receive response */
do {
received_bytes = recv(sock, ptr, sizeof(buffer) - msg_len, 0);
if (received_bytes < 0) {
perror("Error in recv");
return false;
}
nlh = (struct nlmsghdr *) ptr;
/* Check if the header is valid */
if((NLMSG_OK(nlmsg, received_bytes) == 0) ||
(nlmsg->nlmsg_type == NLMSG_ERROR))
{
perror("Error in received packet");
return false;
}
/* If we received all data break */
if (nlh->nlmsg_type == NLMSG_DONE)
break;
else {
ptr += received_bytes;
msg_len += received_bytes;
}
/* Break if its not a multi part message */
if ((nlmsg->nlmsg_flags & NLM_F_MULTI) == 0)
break;
} while ((nlmsg->nlmsg_seq != msgseq) || (nlmsg->nlmsg_pid != getpid()));
/* parse response */
for ( ; NLMSG_OK(nlh, received_bytes); nlh = NLMSG_NEXT(nlh, received_bytes)) {
/* Get the route data */
route_entry = (struct rtmsg *) NLMSG_DATA(nlh);
/* We are just interested in main routing table */
if (route_entry->rtm_table != RT_TABLE_MAIN)
continue;
route_attribute = (struct rtattr *) RTM_RTA(route_entry);
route_attribute_len = RTM_PAYLOAD(nlh);
/* Loop through all attributes */
for ( ; RTA_OK(route_attribute, route_attribute_len);
route_attribute = RTA_NEXT(route_attribute, route_attribute_len)) {
switch(route_attribute->rta_type) {
case RTA_OIF:
if_indextoname(*(int *)RTA_DATA(route_attribute), interface);
break;
case RTA_GATEWAY:
inet_ntop(AF_INET, RTA_DATA(route_attribute),
gateway_address, sizeof(gateway_address));
break;
default:
break;
}
}
if ((*gateway_address) && (*interface)) {
gw.assign(gateway_address);
iface.assign(interface);
break;
} else {
rv = false;
}
}
close(sock);
return true;
}
/*
* 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 Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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 get_gateway_netlink.hpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_GET_GATEWAY_NETLINK_HPP_SEEN
#define FILE_GET_GATEWAY_NETLINK_HPP_SEEN
#include <string>
namespace oai::cn::util {
bool get_iface_l2_addr(const std::string& iface, std::string& mac);
bool get_gateway_and_iface(std::string& gw, std::string& iface);
}
#endif /* FILE_GET_GATEWAY_NETLINK_HPP_SEEN */
/* From https://gist.github.com/javiermon/6272065#file-gateway_netlink-c */
/*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#include "common_defs.h"
#include "if.hpp"
#include "logger.hpp"
#include <errno.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#define BUFFER_SIZE 4096
//------------------------------------------------------------------------------
int get_gateway_and_iface(std::string *gw, std::string *iface)
{
int received_bytes = 0, msg_len = 0, route_attribute_len = 0;
int sock = -1, msgseq = 0;
struct nlmsghdr *nlh, *nlmsg;
struct rtmsg *route_entry;
// This struct contain route attributes (route type)
struct rtattr *route_attribute;
char gateway_address[INET_ADDRSTRLEN], interface[IF_NAMESIZE];
char msgbuf[BUFFER_SIZE], buffer[BUFFER_SIZE];
char *ptr = buffer;
struct timeval tv;
int rv = RETURNok;
if ((sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
Logger::system().error("socket raw/NETLINK_ROUTE failed");
return EXIT_FAILURE;
}
memset(msgbuf, 0, sizeof(msgbuf));
memset(gateway_address, 0, sizeof(gateway_address));
memset(interface, 0, sizeof(interface));
memset(buffer, 0, sizeof(buffer));
/* point the header and the msg structure pointers into the buffer */
nlmsg = (struct nlmsghdr *)msgbuf;
/* Fill in the nlmsg header*/
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nlmsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlmsg->nlmsg_seq = msgseq++; // Sequence of the message packet.
nlmsg->nlmsg_pid = getpid(); // PID of process sending the request.
/* 1 Sec Timeout to avoid stall */
tv.tv_sec = 1;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
/* send msg */
if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) {
Logger::system().error("send socket raw/NETLINK_ROUTE failed");
return EXIT_FAILURE;
}
/* receive response */
do
{
received_bytes = recv(sock, ptr, sizeof(buffer) - msg_len, 0);
if (received_bytes < 0) {
Logger::system().error("recv socket raw/NETLINK_ROUTE failed");
return EXIT_FAILURE;
}
nlh = (struct nlmsghdr *) ptr;
/* Check if the header is valid */
if((NLMSG_OK(nlmsg, received_bytes) == 0) ||
(nlmsg->nlmsg_type == NLMSG_ERROR))
{
Logger::system().error("recv msg raw/NETLINK_ROUTE failed");
return EXIT_FAILURE;
}
/* If we received all data break */
if (nlh->nlmsg_type == NLMSG_DONE)
break;
else {
ptr += received_bytes;
msg_len += received_bytes;
}
/* Break if its not a multi part message */
if ((nlmsg->nlmsg_flags & NLM_F_MULTI) == 0)
break;
}
while ((nlmsg->nlmsg_seq != msgseq) || (nlmsg->nlmsg_pid != getpid()));
/* parse response */
for ( ; NLMSG_OK(nlh, received_bytes); nlh = NLMSG_NEXT(nlh, received_bytes))
{
/* Get the route data */
route_entry = (struct rtmsg *) NLMSG_DATA(nlh);
/* We are just interested in main routing table */
if (route_entry->rtm_table != RT_TABLE_MAIN)
continue;
route_attribute = (struct rtattr *) RTM_RTA(route_entry);
route_attribute_len = RTM_PAYLOAD(nlh);
/* Loop through all attributes */
for ( ; RTA_OK(route_attribute, route_attribute_len);
route_attribute = RTA_NEXT(route_attribute, route_attribute_len))
{
switch(route_attribute->rta_type) {
case RTA_OIF:
if_indextoname(*(int *)RTA_DATA(route_attribute), interface);
break;
case RTA_GATEWAY:
inet_ntop(AF_INET, RTA_DATA(route_attribute),
gateway_address, sizeof(gateway_address));
break;
default:
break;
}
}
if ((*gateway_address) && (*interface)) {
*gw = string(gateway_address);
if (iface) {
*iface = string(interface);
}
break;
} else {
rv = RETURNerror;
}
}
close(sock);
return rv;
}
//------------------------------------------------------------------------------
int get_inet_addr_from_iface(const string& if_name, struct in_addr& inet_addr) {
struct ifreq ifr;
char str[INET_ADDRSTRLEN];
memset(&ifr, 0, sizeof(ifr));
int fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, (const char *)if_name.c_str(), IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFADDR, &ifr)) {
close(fd);
Logger::system().error("Failed to probe %s inet addr: error %s\n", if_name.c_str(), strerror(errno));
return RETURNerror;
}
close(fd);
struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr;
// check
if (inet_ntop(AF_INET, (const void *)&ipaddr->sin_addr, str, INET_ADDRSTRLEN) == NULL) {
return RETURNerror;
}
inet_addr.s_addr = ipaddr->sin_addr.s_addr;
return RETURNok;
}
//------------------------------------------------------------------------------
int get_mtu_from_iface(const string& if_name, uint32_t& mtu) {
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
int fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, (const char *)if_name.c_str(), IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFMTU, &ifr)) {
close(fd);
Logger::system().error("Failed to probe %s MTU: error %s\n", if_name.c_str(), strerror(errno));
return RETURNerror;
}
close(fd);
mtu = ifr.ifr_mtu;
return RETURNok;
}
//------------------------------------------------------------------------------
int get_inet_addr_infos_from_iface(const string& if_name, struct in_addr& inet_addr, struct in_addr& inet_network, unsigned int& mtu) {
struct ifreq ifr;
char str[INET_ADDRSTRLEN];
inet_addr.s_addr = INADDR_ANY;
inet_network.s_addr = INADDR_ANY;
mtu = 0;
memset(&ifr, 0, sizeof(ifr));
int fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, (const char *)if_name.c_str(), IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFADDR, &ifr)) {
close(fd);
Logger::system().error("Failed to probe %s inet addr: error %s\n", if_name.c_str(), strerror(errno));
return RETURNerror;
}
struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr;
// check
if (inet_ntop(AF_INET, (const void *)&ipaddr->sin_addr, str, INET_ADDRSTRLEN) == NULL) {
close(fd);
return RETURNerror;
}
inet_addr.s_addr = ipaddr->sin_addr.s_addr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, (const char *)if_name.c_str(), IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFNETMASK, &ifr)) {
close(fd);
Logger::system().error("Failed to probe %s inet netmask: error %s\n", if_name.c_str(), strerror(errno));
return RETURNerror;
}
ipaddr = (struct sockaddr_in*)&ifr.ifr_netmask;
// check
if (inet_ntop(AF_INET, (const void *)&ipaddr->sin_addr, str, INET_ADDRSTRLEN) == NULL) {
close(fd);
return RETURNerror;
}
inet_network.s_addr = ipaddr->sin_addr.s_addr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, (const char *)if_name.c_str(), IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFMTU, &ifr)) {
Logger::system().error("Failed to probe %s MTU: error %s\n", if_name.c_str(), strerror(errno));
} else {
mtu = ifr.ifr_mtu;
}
close(fd);
return RETURNok;
}
/*
* 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 Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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 get_gateway_netlink.h
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_IF_HPP_SEEN
#define FILE_IF_HPP_SEEN
# include <string>
using namespace std;
int get_gateway_and_iface(string *gw /*OUT*/, string *iface /*OUT*/);
int get_inet_addr_from_iface(const string& if_name, struct in_addr& inet_addr);
int get_mtu_from_iface(const string& if_name, uint32_t& mtu);
int get_inet_addr_infos_from_iface(const string& if_name, struct in_addr& inet_addr, struct in_addr& inet_netmask, unsigned int& mtu);
#endif /* FILE_IF_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 pid_file.cpp
\brief
\author Lionel GAUTHIER
\date 2016
\email: lionel.gauthier@eurecom.fr
*/
#include "logger.hpp"
#include "pid_file.hpp"
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libgen.h>
int g_fd_pid_file = -1;
__pid_t g_pid = -1;
//------------------------------------------------------------------------------
std::string oai::cn::util::get_exe_absolute_path(const std::string &basepath, const unsigned int instance)
{
#define MAX_FILE_PATH_LENGTH 255
char pid_file_name[MAX_FILE_PATH_LENGTH+1] = {0};
char *exe_basename = NULL;
int rv = 0;
int num_chars = 0;
// get executable name
rv = readlink("/proc/self/exe",pid_file_name, 256);
if ( -1 == rv) {
return NULL;
}
pid_file_name[rv] = 0;
exe_basename = basename(pid_file_name);
// Add 6 for the other 5 characters in the path + null terminator + 2 chars for instance.
num_chars = basepath.size() + strlen(exe_basename) + 6 + 2;
if (num_chars > MAX_FILE_PATH_LENGTH) {
num_chars = MAX_FILE_PATH_LENGTH;
}
snprintf(pid_file_name, num_chars, "%s/%s%02u.pid", basepath.c_str(), exe_basename, instance);
return std::string(pid_file_name);
}
//------------------------------------------------------------------------------
int oai::cn::util::lockfile(int fd, int lock_type)
{
// lock on fd only, not on file on disk (do not prevent another process from modifying the file)
return lockf(fd, F_TLOCK, 0);
}
//------------------------------------------------------------------------------
bool oai::cn::util::is_pid_file_lock_success(const char * pid_file_name)
{
char pid_dec[64] = {0};
g_fd_pid_file = open(pid_file_name,
O_RDWR | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* Read/write by owner, read by grp, others */
if ( 0 > g_fd_pid_file) {
Logger::sgwc_app().error( "open filename %s failed %d:%s\n", pid_file_name, errno, strerror(errno));
return false;
}
if ( 0 > oai::cn::util::lockfile(g_fd_pid_file, F_TLOCK)) {
Logger::sgwc_app().error( "lockfile filename %s failed %d:%s\n", pid_file_name, errno, strerror(errno));
if ( EACCES == errno || EAGAIN == errno ) {
close(g_fd_pid_file);
}
return false;
}
// fruncate file content
if (ftruncate(g_fd_pid_file, 0)) {
Logger::sgwc_app().error( "truncate %s failed %d:%s\n", pid_file_name, errno, strerror(errno));
close(g_fd_pid_file);
return false;
}
// write PID in file
g_pid = getpid();
snprintf(pid_dec, 64 /* should be big enough */, "%ld", (long)g_pid);
if ((ssize_t)-1 == write(g_fd_pid_file, pid_dec, strlen(pid_dec))) {
Logger::sgwc_app().error( "write PID to filename %s failed %d:%s\n", pid_file_name, errno, strerror(errno));
return false;
}
return true;
}
//------------------------------------------------------------------------------
void oai::cn::util::pid_file_unlock(void)
{
oai::cn::util::lockfile(g_fd_pid_file, F_ULOCK);
close(g_fd_pid_file);
g_fd_pid_file = -1;
}
/*
* 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 pid_file.hpp
\brief
\author Lionel GAUTHIER
\date 2016
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_PID_FILE_SEEN
#define FILE_PID_FILE_SEEN
#include <string>
namespace oai::cn::util {
/*
* Generate the exe absolute path using a specified base_path.
*
* @param base_path
* the root directory to use.
*
* @return a string for the exe absolute path.
*/
std::string get_exe_absolute_path(const std::string &base_path, const unsigned int instance);
bool is_pid_file_lock_success(const char * pid_file_name);
void pid_file_unlock(void);
int lockfile(int fd, int lock_type);
}
#endif
/*
* 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
*/
#include "string.hpp"
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include <stdarg.h>
template<class T>
class Buffer
{
public:
explicit Buffer(size_t size) { msize = size; mbuf = new T[msize]; }
~Buffer() { if (mbuf) delete [] mbuf; }
T *get() { return mbuf; }
private:
Buffer();
size_t msize;
T *mbuf;
};
std::string oai::cn::util::string_format( const char *format, ... )
{
va_list args;
va_start( args, format );
size_t size = vsnprintf( NULL, 0, format, args ) + 1; // Extra space for '\0'
va_end( args );
Buffer<char> buf( size );
va_start( args, format );
vsnprintf( buf.get(), size, format, args );
va_end( args );
return std::string( buf.get(), size - 1 ); // We don't want the '\0' inside
}
// Licence : https://creativecommons.org/licenses/by-sa/4.0/legalcode
//https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring#217605
// trim from start
std::string &oai::cn::util::ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
// trim from end
std::string &oai::cn::util::rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
// trim from both ends
std::string &oai::cn::util::trim(std::string &s) {
return oai::cn::util::ltrim(oai::cn::util::rtrim(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 string.hpp
\brief
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_STRING_HPP_FILE_SEEN
#define FILE_STRING_HPP_FILE_SEEN
#include <string>
namespace oai::cn::util {
std::string string_format( const char *format, ... );
std::string &ltrim(std::string &s);
// trim from end
std::string &rtrim(std::string &s);
// trim from both ends
std::string &trim(std::string &s);
}
#endif
/*
* 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 uint_uid_generator.hpp
\author Lionel GAUTHIER
\date 2019
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_UINT_GENERATOR_HPP_SEEN
#define FILE_UINT_GENERATOR_HPP_SEEN
#include <mutex>
#include <set>
namespace oai::cn::util {
template <class UINT> class uint_generator {
private:
UINT uid_generator;
std::mutex m_uid_generator;
std::set<UINT> uid_generated;
std::mutex m_uid_generated;
public:
uint_generator() : m_uid_generator() , m_uid_generated() {
uid_generator = 0;
uid_generated = {};
};
uint_generator(uint_generator const&) = delete;
void operator=(uint_generator const&) = delete;
UINT get_uid()
{
std::unique_lock<std::mutex> lr(m_uid_generator);
UINT uid = ++uid_generator;
while (true) {
// may happen race conditions here
std::unique_lock<std::mutex> ld(m_uid_generated);
if (uid_generated.count(uid) == 0) {
uid_generated.insert(uid);
ld.unlock();
lr.unlock();
return uid;
}
uid = ++uid_generator;
}
}
void free_uid(UINT uid)
{
std::unique_lock<std::mutex> l(m_uid_generated);
uid_generated.erase(uid);
l.unlock();
}
};
template <class UINT> class uint_uid_generator {
private:
UINT uid_generator;
std::mutex m_uid_generator;
std::set<UINT> uid_generated;
std::mutex m_uid_generated;
uint_uid_generator() : m_uid_generator() , m_uid_generated() {
uid_generator = 0;
uid_generated = {};
};
public:
static uint_uid_generator& get_instance()
{
static uint_uid_generator instance;
return instance;
}
uint_uid_generator(uint_uid_generator const&) = delete;
void operator=(uint_uid_generator const&) = delete;
UINT get_uid()
{
std::unique_lock<std::mutex> lr(m_uid_generator);
UINT uid = ++uid_generator;
while (true) {
// may happen race conditions here
std::unique_lock<std::mutex> ld(m_uid_generated);
if (uid_generated.count(uid) == 0) {
uid_generated.insert(uid);
lr.unlock();
ld.unlock();
return uid;
}
uid = ++uid_generator;
}
}
void free_uid(UINT uid)
{
std::unique_lock<std::mutex> l(m_uid_generated);
uid_generated.erase(uid);
l.unlock();
}
};
}
#endif // FILE_UINT_GENERATOR_HPP_SEEN
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