Skip to content
sctp_offline_layer.cc 7.45 KiB
Newer Older
#include <chrono>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#include "sctp_offline_layer_factory.hh"

#include "loggers.hh"

sctp_offline_layer::sctp_offline_layer(const std::string& p_type, const std::string& param)
  : layer(p_type), _params(), _time_key("sctp_offline_layer::Handle_Fd_Event_Readable") {
  loggers::get_instance().log(">>> sctp_offline_layer::sctp_offline_layer: '%s', %s", p_type.c_str(), param.c_str());
  params::convert(_params, param);

  _o_params.insert(std::pair<std::string, std::string>(std::string("timestamp"), std::string()));

} // End of ctor

sctp_offline_layer::~sctp_offline_layer() {
  loggers::get_instance().log(">>> sctp_offline_layer::~sctp_offline_layer");
} // End of dtor


void sctp_offline_layer::send_data(OCTETSTRING &p_data, params &p_params) {
  loggers::get_instance().log_msg(">>> sctp_offline_layer::send_data: ", p_data);
  p_params.log();

  // FIXME FSCOM: To be done
  loggers::get_instance().warning("sctp_offline_layer::send_data: Not implemented. Only for offline mode");
  TTCN_Buffer chunk;
  chunk.put_c(0x00); // DATA chunk
  chunk.put_c(0x03); // Flags
  unsigned short l = p_data.lengthof();
  chunk.put_c(l >> 8 & 0xFF); // Data length
  chunk.put_c(l & 0xFF); // Data length
  OCTETSTRING tsn = int2oct(0, 4); // Transmission sequence number
  chunk.put_s(tsn.lengthof(), static_cast<const unsigned char*>(tsn));
  l = 7; // Stream sequence identifier
  chunk.put_c(l >> 8 & 0xFF); // Stream sequence identifier
  chunk.put_c(l & 0xFF); // Stream sequence identifier
  chunk.put_c(0x00); // Stream sequence number
  chunk.put_c(0x00); // Stream sequence number
  OCTETSTRING protocol = int2oct(60, 4); // Protocol is NGAP
  chunk.put_s(protocol.lengthof(), static_cast<const unsigned char*>(protocol));
  chunk.put_s(p_data.lengthof(), static_cast<const unsigned char*>(p_data));
  // FIXME FSCOM: Add padding

  TTCN_Buffer sctp;
  l = 12345; // SCTP Source port
  sctp.put_c(l >> 8 & 0xFF); // Stream sequence identifier
  sctp.put_c(l & 0xFF); // Stream sequence identifier
   l = 12345; // SCTP Destination port
  sctp.put_c(l >> 8 & 0xFF); // Stream sequence identifier
  sctp.put_c(l & 0xFF); // Stream sequence identifier
  OCTETSTRING vt = int2oct(0, 4); // Verification tag
  sctp.put_s(vt.lengthof(), static_cast<const unsigned char*>(vt));
  OCTETSTRING checksum = int2oct(0, 4); // Checksum
  sctp.put_s(checksum.lengthof(), static_cast<const unsigned char*>(checksum));
 
  OCTETSTRING sctp_pdu(sctp.get_read_len(), sctp.get_data());
  sctp_pdu += OCTETSTRING(chunk.get_read_len(), chunk.get_data());
  
  send_to_all_layers(sctp_pdu, static_cast<params&>(p_params));
}

void sctp_offline_layer::receive_data(OCTETSTRING &p_data, params &p_params) {
  loggers::get_instance().log(">>> sctp_offline_layer::receive_data: Received %d bytes", p_data.lengthof());
  loggers::get_instance().log_to_hexa("Packet dump", p_data);

  // Source port
  OCTETSTRING src_port = OCTETSTRING(2, static_cast<const uint8_t *>(p_data));
  loggers::get_instance().log_msg("sctp_offline_layer::receive_data: src_port: ", src_port);
  // Dst port
  OCTETSTRING dst_port = OCTETSTRING(2, 2 + static_cast<const uint8_t *>(p_data));
  loggers::get_instance().log_msg("sctp_offline_layer::receive_data: dst_port: ", dst_port);
  // Verification tag
  OCTETSTRING vtag = OCTETSTRING(4, 4 + static_cast<const uint8_t *>(p_data));
  loggers::get_instance().log_msg("sctp_offline_layer::receive_data: vtag: ", vtag);
  // checksum 
  OCTETSTRING checksum = OCTETSTRING(4, 8 + static_cast<const uint8_t*>(p_data));
  loggers::get_instance().log_msg("sctp_offline_layer::receive_data: checksum: ", checksum);
  // Chunk
  OCTETSTRING chunk = OCTETSTRING(p_data.lengthof() - 12, 12 + static_cast<const uint8_t*>(p_data));
  loggers::get_instance().log_msg("sctp_offline_layer::receive_data: chunk: ", chunk);
  
  OCTETSTRING payload(0, nullptr);
  process_chunk(chunk, p_params, payload);
  if (payload.lengthof() == 0) {
    loggers::get_instance().log("sctp_offline_layer::receive_data: SCTP chunk, skip it");
    return;
  }

  // Update params
  // CHARSTRING s = oct2str(dst);
  // p_params.insert(std::pair<std::string, std::string>(params::ip_dst, std::string(static_cast<const char *>(s))));
  // s = oct2str(src);
  // p_params.insert(std::pair<std::string, std::string>(params::ip_src, std::string(static_cast<const char *>(s))));
  // s = oct2str(protocol);
  // p_params.insert(std::pair<std::string, std::string>(params::ip_proto, std::string(static_cast<const char *>(s))));
  // Pass the packet to the upper layers
  receive_to_all_layers(payload, p_params);
}

void sctp_offline_layer::process_chunk(const OCTETSTRING& p_chunk, params &p_params, OCTETSTRING& p_payload) {
  loggers::get_instance().log_msg(">>> sctp_offline_layer::process_chunk: ", p_chunk);

  const uint8_t* p = static_cast<const uint8_t*>(p_chunk); // Chunk type
  switch (static_cast<const uint8_t>(*p)) {
    case 0x00: { // DATA chunk
        p += 2; // Skip Chunk type + Chunk flag
        // Chunk length
        uint16_t l = (*p << 8 | *(p + 1)) & 0xffff;
Yann Garcia's avatar
Yann Garcia committed
        loggers::get_instance().log("sctp_offline_layer::process_chunk: l: %d", l);
        p += 2;

        p += 4; // Skip Transmission sequence number

        // Stream identifier
        OCTETSTRING stream_id = OCTETSTRING(2, p);
Yann Garcia's avatar
Yann Garcia committed
        loggers::get_instance().log_msg("sctp_offline_layer::process_chunk: stream_id: ", stream_id);
        p += 2;
        // Stream sequence number
        OCTETSTRING stream_num = OCTETSTRING(2, p);
Yann Garcia's avatar
Yann Garcia committed
        loggers::get_instance().log_msg("sctp_offline_layer::process_chunk: stream_num: ", stream_num);
        p += 2;
        // Protocol
        uint32_t protocol = (*p << 24 | *(p + 1) << 16 | *(p + 2) << 8 | *(p + 3)) & 0xffffffff;
Yann Garcia's avatar
Yann Garcia committed
        loggers::get_instance().log("sctp_offline_layer::process_chunk: protocol: %d", protocol);
        p += 4;
Yann Garcia's avatar
Yann Garcia committed
        loggers::get_instance().log("sctp_offline_layer::process_chunk: pointer offset: %d", (uint32_t)(p - static_cast<const uint8_t*>(p_chunk)));
        p_payload = OCTETSTRING(p_chunk.lengthof() - (uint32_t)(p - static_cast<const uint8_t*>(p_chunk)), p);
      }
      break;
    case 0x01: // INIT chunk
      break;
    case 0x02: // INIT_ACK chunk
      break;
Yann Garcia's avatar
Yann Garcia committed
    case 0x03: { // SACK
        loggers::get_instance().log("sctp_offline_layer::process_chunk (SACK): position: %02x", static_cast<const uint8_t>(*(p)));
        const uint8_t f = static_cast<const uint8_t>(*(p + 1));
        loggers::get_instance().log("sctp_offline_layer::process_chunk (SACK): flags: %04x", f);
        const uint16_t l = static_cast<const uint16_t>((*(p + 2) << 8 | *(p + 3)) & 0xffff);
        loggers::get_instance().log("sctp_offline_layer::process_chunk (SACK): length: %d", l);
        loggers::get_instance().log("sctp_offline_layer::process_chunk (SACK): p_chunk.lengthof(): %d", p_chunk.lengthof());
        if (p_chunk.lengthof() > l) {
          // Extract and process the next chunk
          OCTETSTRING chunk(p_chunk.lengthof() - l, p + l);
          process_chunk(chunk, p_params, p_payload);
        }
      }
      break;
    case 0x04: // HEARTBEAT
      break;
    case 0x05: // HEARTBEAT_ACK
      break;
    case 0x0a: // COOKIE_ECHO chunk
      break;
    case 0x0b: // COOKIE_ACK chunk
      break;
    default: //
Yann Garcia's avatar
Yann Garcia committed
      loggers::get_instance().warning("sctp_offline_layer::process_chunk: Unprocessed chunk: 0x%02x", *p);
  }

  loggers::get_instance().log_msg("<<< sctp_offline_layer::process_chunk: p_payload: ", p_payload);
}

sctp_offline_layer_factory sctp_offline_layer_factory::_f;