Commit 80aa8d27 authored by Yann Garcia's avatar Yann Garcia
Browse files

Adding GTP-U support miissing files

parent 2854ca1e
Loading
Loading
Loading
Loading
+126 −0
Changes for ccsrc/Ports/LibGtpu/GtpuPort.cc: 126 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*!
 * \file      GtpuPort.cc
 * \brief     CC file for GtpuPort.
 * \author    ETSI TTF T059
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */

#include "loggers.hh"

#include "LibGtpu_Interface.hh"
#include "LibGtpu_TypesAndValues.hh"
#include "gtpu_layer_factory.hh"
#include "layer.hh"
#include "params.hh"

namespace LibGtpu__TypesAndValues {
  class GtpuMessage;
}
namespace LibGtpu__Interface {

  GtpuPort::GtpuPort(const char *par_port_name): GtpuPort_BASE(par_port_name), _cfg_params(), _layer_params(), _layer(nullptr), _time_key("GtpuPort::") {
    // Nothing to do
  } // End of constructor

  GtpuPort::~GtpuPort() {
    loggers::get_instance().log(">>> GtpuPort::~GtpuPort");

    if (_layer != nullptr) {
      delete _layer;
    }
  } // End of destructor

  void GtpuPort::set_parameter(const char * parameter_name, const char * parameter_value)
  {
    loggers::get_instance().log("GtpuPort::set_parameter: %s=%s", parameter_name, parameter_value);
    _cfg_params.insert(std::pair<std::string, std::string>(std::string(parameter_name), std::string(parameter_value)));
  }

  void GtpuPort::Handle_Fd_Event_Error(int /*fd*/)
  {

  }

  void GtpuPort::Handle_Fd_Event_Writable(int /*fd*/)
  {

  }

  void GtpuPort::Handle_Fd_Event_Readable(int /*fd*/)
  {

  }

  void GtpuPort::user_map(const char * system_port)
  {
    loggers::get_instance().log(">>> GtpuPort::user_map: %s", system_port);
    // Build layer stack
    params::iterator it = _cfg_params.find(std::string("params"));
    if (it != _cfg_params.end()) {
      loggers::get_instance().log("GtpuPort::user_map: %s", it->second.c_str());
      // Setup parameters
      params::convert(_layer_params, it->second); // TODO This _layer_params seems to be useless
      // Create layer
      _layer = layer_stack_builder::get_instance()->create_layer_stack(it->second.c_str());

      if (static_cast<gtpu_layer*>(_layer) == nullptr) {
        loggers::get_instance().error("GtpuPort::user_map: Invalid stack configuration - NOT GTPU: %s", it->second.c_str());
      }
      static_cast<gtpu_layer*>(_layer)->add_upper_port(this);
    } else {
      loggers::get_instance().error("GtpuPort::user_map: No layers defined in configuration file");
    }
  } // End of user_map method

  void GtpuPort::user_unmap(const char * system_port)
  {
    loggers::get_instance().log(">>> GtpuPort:user_unmap: %s", system_port);

    // Reset layers
    if (_layer != nullptr) {
      delete _layer;
      _layer = nullptr;
    }
  } // End of user_unmap method

  void GtpuPort::user_start()
  {
    loggers::get_instance().log(">>> GtpuPort::user_start");

  } // End of user_start method

  void GtpuPort::user_stop()
  {
    loggers::get_instance().log(">>> GtpuPort::user_stop");

  } // End of user_stop method

  void GtpuPort::outgoing_send(const LibGtpu__TypesAndValues::GtpuMessage& send_par)
  {
    loggers::get_instance().log_msg(">>> GtpuPort::outgoing_send: payload=", send_par);

    float duration;
    loggers::get_instance().set_start_time(_time_key);
    params params;
        static_cast<gtpu_layer*>(_layer)->sendMsg(send_par, params);
    loggers::get_instance().set_stop_time(_time_key, duration);
  }

  void GtpuPort::receiveMsg (const  LibGtpu__TypesAndValues::GtpuMessage& p_ind, const params& p_params) {
    loggers::get_instance().log_msg(">>> GtpuPort::receive_msg: ", p_ind);
    float duration;
    loggers::get_instance().set_start_time(_time_key);
    // Sanity check
    if (!p_ind.is_bound()) {
      return;
    }

    incoming_message(p_ind);
    loggers::get_instance().set_stop_time(_time_key, duration);
  }

} // End of namespace LibGtpu__Interface
+54 −0
Changes for ccsrc/Ports/LibGtpu/GtpuPort.hh: 54 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*!
 * \file      GtpuPort.hh
 * \brief     Header file for GtpuPort.
 * \author    ETSI TTF T059
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */

#pragma once

#include "LibGtpu_Interface.hh"
#include "LibGtpu_TypesAndValues.hh"

#include "layer.hh"
#include "params.hh"

namespace LibGtpu__TypesAndValues {
  class GtpuMessage;
}
namespace LibGtpu__Interface {

  class  GtpuPort : public GtpuPort_BASE {
    params _cfg_params;
    params _layer_params;
    layer* _layer;
    std::string _time_key;
  public:
     GtpuPort(const char *par_port_name);
    ~ GtpuPort();

    void set_parameter(const char *parameter_name, const char *parameter_value);
    void receiveMsg (const LibGtpu__TypesAndValues::GtpuMessage& p_ind, const params& p_params);

  private:
    void Handle_Fd_Event_Error(int fd);
    void Handle_Fd_Event_Writable(int fd);
    void Handle_Fd_Event_Readable(int fd);

  protected:
    const char *port_name;
    void user_map(const char *system_port);
    void user_unmap(const char *system_port);

    void user_start();
    void user_stop();

  protected:
    void outgoing_send(const LibGtpu__TypesAndValues::GtpuMessage& send_par);
  }; // End of class  GtpuPort

} // End of namespace LibGtpu__Interface
+2 −0
Changes for ccsrc/Ports/LibGtpu/module.mk: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
sources := GtpuPort.cc
includes := .
+148 −0
Changes for ccsrc/Protocols/Gtpu/gtpu_codec.cc: 148 added lines, 0 removed lines.
Original line number Diff line number Diff line
#include "gtpu_codec.hh"

#include "LibGtpu_TypesAndValues.hh"

#include "loggers.hh"

namespace {
  const uint8_t GTPU_FLAGS_BASE = 0x30; // Version 1, protocol type GTP (3GPP TS 29.281 clause 5.1)
  const uint8_t GTPU_FLAG_E     = 0x04; // Extension header present
  const uint8_t GTPU_FLAG_S     = 0x02; // Sequence number present
  const uint8_t GTPU_FLAG_PN    = 0x01; // N-PDU number present
} // namespace

int gtpu_codec::encode(const LibGtpu__TypesAndValues::GtpuMessage& p_msg, OCTETSTRING& p_data) {
  loggers::get_instance().log_msg(">>> gtpu_codec::encode: ", p_msg);

  const LibGtpu__TypesAndValues::GtpuHeader& hdr = p_msg.header();
  const bool s  = hdr.sequenceNumber().ispresent();
  const bool pn = hdr.npduNumber().ispresent();
  int        nb_ext = 0;
  if (hdr.extensionHeaders().ispresent()) {
    nb_ext = static_cast<const LibGtpu__TypesAndValues::GtpuExtensionHeaders&>(*hdr.extensionHeaders().get_opt_value()).size_of();
  }
  const bool e = nb_ext > 0;

  // Everything after the mandatory 8 octets: optional fields, extension headers and payload
  TTCN_Buffer rest;
  if (e || s || pn) {
    const int seq  = s ? static_cast<int>(static_cast<const INTEGER&>(*hdr.sequenceNumber().get_opt_value())) : 0;
    const int npdu = pn ? static_cast<int>(static_cast<const INTEGER&>(*hdr.npduNumber().get_opt_value())) : 0;
    rest.put_c(static_cast<unsigned char>((seq >> 8) & 0xFF));
    rest.put_c(static_cast<unsigned char>(seq & 0xFF));
    rest.put_c(static_cast<unsigned char>(npdu & 0xFF));
    if (e) {
      const LibGtpu__TypesAndValues::GtpuExtensionHeaders& exts =
        static_cast<const LibGtpu__TypesAndValues::GtpuExtensionHeaders&>(*hdr.extensionHeaders().get_opt_value());
      rest.put_c(static_cast<unsigned char>(static_cast<int>(exts[0].headerType())));
      for (int i = 0; i < nb_ext; i++) {
        const OCTETSTRING& content = exts[i].content();
        int total = content.lengthof() + 2; // + length octet + next extension header type octet
        int pad   = (4 - (total % 4)) % 4;
        total += pad;
        if (total / 4 > 255) {
          loggers::get_instance().warning("gtpu_codec::encode: Extension header %d too long", i);
          return -1;
        }
        rest.put_c(static_cast<unsigned char>(total / 4));
        rest.put_os(content);
        for (int j = 0; j < pad; j++) {
          rest.put_c(0x00);
        }
        rest.put_c(static_cast<unsigned char>((i + 1 < nb_ext) ? static_cast<int>(exts[i + 1].headerType()) : 0));
      } // End of 'for' statement
    } else {
      rest.put_c(0x00); // No more extension headers
    }
  }
  rest.put_os(p_msg.payload());
  if (rest.get_len() > 0xFFFF) {
    loggers::get_instance().warning("gtpu_codec::encode: Message too long: %zu", rest.get_len());
    return -1;
  }

  TTCN_Buffer buffer;
  buffer.put_c(static_cast<unsigned char>(GTPU_FLAGS_BASE | (e ? GTPU_FLAG_E : 0) | (s ? GTPU_FLAG_S : 0) | (pn ? GTPU_FLAG_PN : 0)));
  buffer.put_c(static_cast<unsigned char>(static_cast<int>(hdr.messageType())));
  buffer.put_c(static_cast<unsigned char>((rest.get_len() >> 8) & 0xFF));
  buffer.put_c(static_cast<unsigned char>(rest.get_len() & 0xFF));
  buffer.put_os(hdr.teid());
  buffer.put_s(rest.get_len(), rest.get_data());

  p_data = OCTETSTRING(buffer.get_len(), buffer.get_data());
  loggers::get_instance().log_msg("<<< gtpu_codec::encode: ", p_data);
  return 0;
}

int gtpu_codec::decode(const OCTETSTRING& p_data, LibGtpu__TypesAndValues::GtpuMessage& p_msg) {
  loggers::get_instance().log_msg(">>> gtpu_codec::decode: ", p_data);

  const unsigned char* b = static_cast<const unsigned char*>(p_data);
  const uint32_t       n = static_cast<uint32_t>(p_data.lengthof());
  if (n < 8) {
    loggers::get_instance().warning("gtpu_codec::decode: Truncated header (%u bytes)", n);
    return -1;
  }
  if (((b[0] >> 5) != 1) || ((b[0] & 0x10) == 0)) {
    loggers::get_instance().warning("gtpu_codec::decode: Not GTPv1-U: first octet 0x%02x", b[0]);
    return -1;
  }
  const bool     e   = (b[0] & GTPU_FLAG_E) != 0;
  const bool     s   = (b[0] & GTPU_FLAG_S) != 0;
  const bool     pn  = (b[0] & GTPU_FLAG_PN) != 0;
  const uint32_t len = (static_cast<uint32_t>(b[2]) << 8) | b[3];
  const uint32_t end = 8 + len;
  if (end > n) {
    loggers::get_instance().warning("gtpu_codec::decode: Truncated message (%u bytes available, %u required)", n, end);
    return -1;
  }

  LibGtpu__TypesAndValues::GtpuHeader& hdr = p_msg.header();
  hdr.messageType() = static_cast<int>(b[1]);
  hdr.teid()        = OCTETSTRING(4, b + 4);
  hdr.sequenceNumber().set_to_omit();
  hdr.npduNumber().set_to_omit();
  hdr.extensionHeaders().set_to_omit();

  uint32_t off  = 8;
  uint8_t  next = 0;
  if (e || s || pn) {
    if (off + 4 > end) {
      loggers::get_instance().warning("gtpu_codec::decode: Truncated optional fields");
      return -1;
    }
    if (s) {
      hdr.sequenceNumber() = static_cast<int>((static_cast<uint32_t>(b[off]) << 8) | b[off + 1]);
    }
    if (pn) {
      hdr.npduNumber() = static_cast<int>(b[off + 2]);
    }
    next = e ? b[off + 3] : 0;
    off += 4;
  }
  if (e) {
    LibGtpu__TypesAndValues::GtpuExtensionHeaders exts(NULL_VALUE);
    int                                           i = 0;
    while (next != 0) {
      if (off + 1 > end) {
        loggers::get_instance().warning("gtpu_codec::decode: Truncated extension header");
        return -1;
      }
      const uint32_t l = static_cast<uint32_t>(b[off]) * 4;
      if ((l == 0) || (off + l > end)) {
        loggers::get_instance().warning("gtpu_codec::decode: Invalid extension header length: %u", l);
        return -1;
      }
      exts[i].headerType() = static_cast<int>(next);
      exts[i].content()    = OCTETSTRING(l - 2, b + off + 1);
      next                 = b[off + l - 1];
      off += l;
      i++;
    } // End of 'while' statement
    hdr.extensionHeaders() = exts;
  }
  p_msg.payload() = OCTETSTRING(end - off, b + off);

  loggers::get_instance().log_msg("<<< gtpu_codec::decode: ", p_msg);
  return 0;
}
+50 −0
Changes for ccsrc/Protocols/Gtpu/gtpu_codec.hh: 50 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*!
 * \file      gtpu_codec.hh
 * \brief     Header file for the GTP-U typed message codec.
 * \author    ETSI TTF T059
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */
#pragma once

#include <cstdint>

class OCTETSTRING; //! Forward declaration of TITAN class

namespace LibGtpu__TypesAndValues {
  class GtpuMessage; //! Forward declaration of TITAN class
} // namespace LibGtpu__TypesAndValues

/*!
 * \class gtpu_codec
 * \brief  Converts between the typed \c GtpuMessage TTCN-3 record and its GTP-U (3GPP TS 29.281 clause 5)
 *         wire encoding: the mandatory header, the optional sequence number, N-PDU number and extension
 *         headers, and the payload (the T-PDU of a G-PDU).
 */
class gtpu_codec {
public: //! \publicsection
  explicit gtpu_codec(){};
  virtual ~gtpu_codec(){};

  /*!
   * \fn int encode(const LibGtpu__TypesAndValues::GtpuMessage& p_msg, OCTETSTRING& p_data);
   * \brief  Encode a typed GTP-U message. The E, S and PN flags are set from the presence of the
   *         extension headers, the sequence number and the N-PDU number; the contents of each extension
   *         header are padded with zeros to a multiple of 4 octets, as clause 5.2.1 requires.
   * \param[in] p_msg The typed message to be encoded
   * \param[out] p_data The encoding result
   * \return 0 on success, -1 otherwise
   */
  virtual int encode(const LibGtpu__TypesAndValues::GtpuMessage& p_msg, OCTETSTRING& p_data);
  /*!
   * \fn int decode(const OCTETSTRING& p_data, LibGtpu__TypesAndValues::GtpuMessage& p_msg);
   * \brief  Decode a GTP-U message. Octets after the length given in the header are ignored.
   * \param[in] p_data The message octets (one UDP payload)
   * \param[out] p_msg The resulting typed message
   * \return 0 on success, -1 if the message is truncated or is not GTP version 1 with the protocol type GTP
   */
  virtual int decode(const OCTETSTRING& p_data, LibGtpu__TypesAndValues::GtpuMessage& p_msg);
}; // End of class gtpu_codec
Loading