Exemple #1
0
/*
 * rbu_findChunk: looks for chunk_type in a newly received datagram
 *
 * All chunks within the datagram are looked at, until one is found
 * that equals the parameter chunk_type.
 * @param  datagram     pointer to the newly received data
 * @param  len          stop after this many bytes
 * @param  chunk_type   chunk type to look for
 * @return pointer to first chunk of chunk_type in SCTP datagram, else NULL
 */
guchar* rbu_findChunk(guchar * datagram, guint len, gushort chunk_type)
{
    gushort processed_len = 0, chunk_len = 0;
    guchar *current_position;
    guint pad_bytes;
    SCTP_simple_chunk *chunk;

    current_position = datagram; /* points to the first chunk in this pdu */
    while (processed_len < len) {

        event_logii(INTERNAL_EVENT_0,
                    "rbu_findChunk : len==%u, processed_len == %u", len, processed_len);

        chunk = (SCTP_simple_chunk *) current_position;
        if (chunk->chunk_header.chunk_id == chunk_type)
            return current_position;
        else {
            chunk_len = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
            if (chunk_len < 4 || chunk_len + processed_len > len) return NULL;

            processed_len += CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
            pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
            processed_len += pad_bytes;
            chunk_len = (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) + pad_bytes * sizeof(unsigned char));
            if (chunk_len < 4 || chunk_len + processed_len > len) return NULL;
            current_position += chunk_len;
        }
    }
    return NULL;
}
Exemple #2
0
void print_time(short level)
{
    struct timeval now;

    adl_gettime(&now);
    event_logii(level, "Time now: %ld sec, %ld usec \n", now.tv_sec, now.tv_usec);
}
/**
 * this function used for bundling of control chunks
 * Used by SCTP-control and Path management
 *
 * @param chunk pointer to chunk, that is to be put in the bundling buffer
 * @return TODO : error value, 0 on success
 */
gint
bu_put_Ctrl_Chunk (SCTP_simple_chunk * chunk, unsigned int * dest_index)
{
  gint result;
  bundling_instance *bu_ptr;
  gint count;
  gboolean lock;

  event_log(INTERNAL_EVENT_0, "bu_put_Ctrl_Chunk() was called");

  bu_ptr = (bundling_instance *) mdi_readBundling ();

  if (!bu_ptr)
  { /* Assume that no association exists, so we take the global bundling buffer */
    event_log(VERBOSE, "Copying Control Chunk to global bundling buffer ");
    bu_ptr = global_buffer;
  }

  if (TOTAL_SIZE(bu_ptr) + CHUNKP_LENGTH((chunk_fixed_t * ) chunk)
      >= MAX_SCTP_PDU)
  {
    lock = bu_ptr->locked;
    event_logi(
        VERBOSE,
        "Chunk Length exceeded MAX_SCTP_PDU : sending chunk to address %u !",
        (dest_index==NULL)?0:*dest_index);
    if (lock)
      bu_ptr->locked = FALSE;
    result = bu_sendAllChunks (dest_index);
    if (lock)
      bu_ptr->locked = TRUE;
  }
  else if (dest_index != NULL)
  {
    bu_ptr->got_send_address = TRUE;
    bu_ptr->requested_destination = *dest_index;
  }

  memcpy (&(bu_ptr->ctrl_buf[bu_ptr->ctrl_position]), chunk,
          CHUNKP_LENGTH((chunk_fixed_t * ) chunk));
  bu_ptr->ctrl_position += CHUNKP_LENGTH((chunk_fixed_t * ) chunk);
  /* insert padding, if necessary */
  if ((CHUNKP_LENGTH((chunk_fixed_t *) chunk) % 4) != 0)
  {
    for (count = 0; count < (4 - (CHUNKP_LENGTH((chunk_fixed_t *) chunk) % 4));
        count++)
    {
      bu_ptr->ctrl_buf[bu_ptr->ctrl_position] = 0;
      bu_ptr->ctrl_position++;
    }
  }
  event_logii(
      VERBOSE,
      "Put Control Chunk Length : %u , Total buffer size now (includes pad): %u\n",
      CHUNKP_LENGTH((chunk_fixed_t *) chunk), TOTAL_SIZE(bu_ptr));

  bu_ptr->ctrl_chunk_in_buffer = TRUE;
  return 0;
}
/**
 * Called by recvcontrol, when a SACK must be piggy-backed
 * TODO : Handle multiple calls to this function between two send events
 *
 * @param chunk pointer to chunk, that is to be put in the bundling buffer
 * @return error value, 0 on success, -1 on error
 */
gint
bu_put_SACK_Chunk (SCTP_sack_chunk * chunk, unsigned int * dest_index)
{
  gint result;
  bundling_instance *bu_ptr;
  gboolean lock;

  event_log(INTERNAL_EVENT_0, "bu_put_SACK_Chunk() was called ");

  bu_ptr = (bundling_instance *) mdi_readBundling ();

  if (!bu_ptr)
  { /* Assume that no association exists, so we take the global bundling buffer */
    event_log(VERBOSE, "Copying SACK to global bundling buffer ");
    bu_ptr = global_buffer;
  }

  if (SACK_SIZE(bu_ptr) + CHUNKP_LENGTH((chunk_fixed_t * ) chunk)
      >= MAX_SCTP_PDU)
  {
    lock = bu_ptr->locked;
    event_logi(
        VERBOSE,
        "Chunk Length exceeded MAX_SCTP_PDU : sending chunk to address %u !",
        (dest_index==NULL)?0:*dest_index);
    if (lock)
      bu_ptr->locked = FALSE;
    result = bu_sendAllChunks (dest_index);
    if (lock)
      bu_ptr->locked = TRUE;
  }
  else if (dest_index != NULL)
  {
    bu_ptr->got_send_address = TRUE;
    bu_ptr->requested_destination = *dest_index;
  }

  if (bu_ptr->sack_in_buffer == TRUE)
  { /* multiple calls in between */
    event_log(
        INTERNAL_EVENT_0,
        "bu_put_SACK_Chunk was called a second time, deleting first chunk");
    bu_ptr->sack_position = sizeof(SCTP_common_header);
  }

  memcpy (&(bu_ptr->sack_buf[bu_ptr->sack_position]), chunk,
          CHUNKP_LENGTH((chunk_fixed_t * ) chunk));
  bu_ptr->sack_position += CHUNKP_LENGTH((chunk_fixed_t * ) chunk);
  bu_ptr->sack_in_buffer = TRUE;

  event_logii(VERBOSE,
              "Put SACK Chunk Length : %u , Total buffer size now: %u\n",
              CHUNKP_LENGTH((chunk_fixed_t *) chunk), TOTAL_SIZE(bu_ptr));

  /* SACK always multiple of 32 bytes, do not care about padding */
  return 0;
}
Exemple #5
0
/**
 * looks for Error chunk_type in a newly received datagram
 * that contains a special error cause code
 *
 * All chunks within the datagram are lookes at, until one is found
 * that equals the parameter chunk_type.
 * @param  datagram     pointer to the newly received data
 * @param  len          stop after this many bytes
 * @param  error_cause  error cause code to look for
 * @return true is chunk_type exists in SCTP datagram, false if it is not in there
 */
gboolean rbu_scanDatagramForError(guchar * datagram, guint len, gushort error_cause)
{
    gushort processed_len = 0, param_length = 0, chunk_length = 0;
    gushort err_len = 0;

    guchar *current_position;
    guint pad_bytes;
    SCTP_simple_chunk *chunk;
    SCTP_staleCookieError *err_chunk;


    current_position = datagram; /* points to the first chunk in this pdu */
    while (processed_len < len) {

        event_logii(VERBOSE,
                    "rbu_scanDatagramForError : len==%u, processed_len == %u", len, processed_len);

        chunk = (SCTP_simple_chunk *) current_position;
        chunk_length = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
        if (chunk_length < 4 || chunk_length + processed_len > len) return FALSE;

        if (chunk->chunk_header.chunk_id == CHUNK_ERROR) {

            if (chunk_length < 4 || chunk_length + processed_len > len) return FALSE;

            event_log(INTERNAL_EVENT_0, "rbu_scanDatagramForError : Error Chunk Found");
            /* now search for error parameter that fits */
            while (err_len < chunk_length - sizeof(SCTP_chunk_header))  {
                err_chunk = (SCTP_staleCookieError *) &(chunk->simple_chunk_data[err_len]);
                if (ntohs(err_chunk->vlparam_header.param_type) == error_cause) {
                    event_logi(VERBOSE,
                               "rbu_scanDatagramForError : Error Cause %u found -> Returning TRUE",
                               error_cause);
                    return TRUE;
                }
                param_length = ntohs(err_chunk->vlparam_header.param_length);
                if (param_length < 4 || param_length + err_len > len) return FALSE;

                err_len += param_length;
                while ((err_len % 4) != 0)
                    err_len++;
            }
        }

        processed_len += chunk_length;
        pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
        processed_len += pad_bytes;
        chunk_length = (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) + pad_bytes * sizeof(unsigned char));
        if (chunk_length < 4 || chunk_length + processed_len > len) return FALSE;
        current_position += chunk_length;
    }
    event_logi(VERBOSE,
               "rbu_scanDatagramForError : Error Cause %u NOT found -> Returning FALSE",
               error_cause);
    return FALSE;
}
Exemple #6
0
unsigned int rbu_scanPDU(guchar * pdu, guint len)
{
    gushort processed_len = 0;
    gushort chunk_len = 0;
    unsigned int result = 0;
    guchar *current_position;
    guint pad_bytes;
    SCTP_simple_chunk *chunk;

    current_position = pdu; /* points to the first chunk in this pdu */

    while (processed_len < len) {

        event_logii(VERBOSE, "rbu_scanPDU : len==%u, processed_len == %u", len, processed_len);

        chunk = (SCTP_simple_chunk *) current_position;
        chunk_len = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);

        if (chunk_len < 4 || chunk_len + processed_len > len) return result;

        if (chunk->chunk_header.chunk_id <= 30) {
            result = result | (1 << chunk->chunk_header.chunk_id);
            event_logii(VERBOSE, "rbu_scanPDU : Chunk type==%u, result == %x", chunk->chunk_header.chunk_id, result);
        } else {
            result = result | (1 << 31);
            event_logii(VERBOSE, "rbu_scanPDU : Chunk type==%u setting bit 31 --> result == %x", chunk->chunk_header.chunk_id, result);
        }
        processed_len += chunk_len;
        pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
        processed_len += pad_bytes;
        chunk_len = (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) + pad_bytes * sizeof(unsigned char));

        if (chunk_len < 4 || chunk_len + processed_len > len) return result;
        current_position += chunk_len;

    }
    return result;
}
/**
 * this function used for putting data chunks into the buffer
 * Used only in the flow control module
 *
 * @param chunk pointer to chunk, that is to be put in the bundling buffer
 * @return TODO : error value, 0 on success
 */
gint bu_put_Data_Chunk(SCTP_simple_chunk * chunk,unsigned int * dest_index)
{
    bundling_instance *bu_ptr;
    gint count;
    gboolean lock;

    event_log(INTERNAL_EVENT_0, "bu_put_Data_Chunk() was called ");

    bu_ptr = (bundling_instance *) mdi_readBundling();

    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Copying data to global bundling buffer ");
        bu_ptr = global_buffer;
    }

    if (TOTAL_SIZE(bu_ptr) + CHUNKP_LENGTH((SCTP_chunk_header *) chunk) >= MAX_SCTP_PDU) {
        lock = bu_ptr->locked;
        event_logi(VERBOSE,
                  "Chunk Length exceeded MAX_SCTP_PDU : sending chunk to address %u !",
                    (dest_index==NULL)?0:*dest_index);
        if (lock) bu_ptr->locked = FALSE;
        bu_sendAllChunks(dest_index);
        if (lock) bu_ptr->locked = TRUE;
    } else if (dest_index != NULL) {
        bu_ptr->got_send_address = TRUE;
        bu_ptr->requested_destination = *dest_index;
    }
    memcpy(&(bu_ptr->data_buf[bu_ptr->data_position]), chunk,
           CHUNKP_LENGTH((SCTP_chunk_header *) chunk));
    bu_ptr->data_position += CHUNKP_LENGTH((SCTP_chunk_header *) chunk);


    /* insert padding, if necessary */
    if ((CHUNKP_LENGTH((SCTP_chunk_header *) chunk) % 4) != 0) {
        for (count = 0; count < (4 - (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) % 4)); count++) {
            bu_ptr->data_buf[bu_ptr->data_position] = 0;
            bu_ptr->data_position++;
        }
    }
    event_logii(VERBOSE, "Put Data Chunk Length : %u , Total buffer size (incl. padding): %u\n",
                CHUNKP_LENGTH((SCTP_chunk_header *) chunk), TOTAL_SIZE(bu_ptr));

    bu_ptr->data_in_buffer = TRUE;

    /* if SACK is waiting, force sending it along */
    if (rxc_sack_timer_is_running() == TRUE) rxc_create_sack(dest_index, TRUE);

    return 0;
}
Exemple #8
0
guchar* rbu_scanInitChunkForParameter(guchar * chunk, gushort paramType)
{
    gushort processed_len;
    guint len = 0, parameterLength = 0;
    guchar *current_position;
    guint pad_bytes;
    SCTP_init *initChunk;
    SCTP_vlparam_header* vlp;

    initChunk = (SCTP_init *) chunk;

    if (initChunk->chunk_header.chunk_id != CHUNK_INIT &&
        initChunk->chunk_header.chunk_id != CHUNK_INIT_ACK) {
        return FALSE;
    }
    len = ntohs(initChunk->chunk_header.chunk_length);
    current_position = initChunk->variableParams;
    processed_len = (sizeof(SCTP_chunk_header)+sizeof(SCTP_init_fixed));

    while (processed_len < len) {
        event_logii(INTERNAL_EVENT_0,
                    "rbu_scanInitChunkForParameter : len==%u, processed_len == %u", len, processed_len);
        vlp = (SCTP_vlparam_header*) current_position;
        parameterLength = ntohs(vlp->param_length);

        if (parameterLength < 4 || parameterLength + processed_len > len) return NULL;

        if (ntohs(vlp->param_type) == paramType) {
            return current_position;
        }
        processed_len += parameterLength;
        pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
        processed_len += pad_bytes;
        current_position += (parameterLength + pad_bytes * sizeof(unsigned char));
    }
    return NULL;

}
/**
 * Trigger sending of all chunks previously entered with put_Chunk functions
 *  Chunks sent are deleted afterwards.
 *
 * FIXME : special treatment for GLOBAL BUFFER, as this is not associated with
 *         any association.
 *
 *
 *  @return                 Errorcode (0 for good case: length bytes sent; 1 or -1 for error)
 *  @param   ad_idx     pointer to address index or NULL if data is to be sent to default address
 */
gint bu_sendAllChunks(guint * ad_idx)
{
    gint result, send_len = 0;
    guchar *send_buffer = NULL;
    bundling_instance *bu_ptr;
    gshort idx = 0;

    bu_ptr = (bundling_instance *) mdi_readBundling();

    event_log(INTERNAL_EVENT_0, "bu_sendAllChunks() is being executed...");

    if (!bu_ptr) {
        event_log(VERBOSE, "Sending data from global bundling buffer ");
        bu_ptr = global_buffer;
    }
    if (bu_ptr->locked == TRUE) {
        bu_ptr->got_send_request = TRUE;
        if (ad_idx) {
            bu_ptr->got_send_address = TRUE;
            bu_ptr->requested_destination = *ad_idx;
        }
        event_log(INTERNAL_EVENT_0, "bu_sendAllChunks : sender is LOCKED ---> returning ");
        return 1;
    }

    /* TODO : more intelligent path selection strategy */
    /*         should take into account PM_INACTIVE */
    if (ad_idx != NULL) {
        if (*ad_idx > 0xFFFF) {
            error_log(ERROR_FATAL, "address_index too big !");
        } else {
            idx = (short) *ad_idx;
        }
    } else {
        if (bu_ptr->got_send_address) {
            idx = (short)bu_ptr->requested_destination;
        } else {
            idx = -1; /* use last from address */
        }
    }

    event_logi(VVERBOSE, "bu_sendAllChunks : send to path %d ", idx);

    if (bu_ptr->sack_in_buffer)             send_buffer = bu_ptr->sack_buf;
    else if (bu_ptr->ctrl_chunk_in_buffer)  send_buffer = bu_ptr->ctrl_buf;
    else if (bu_ptr->data_in_buffer)        send_buffer = bu_ptr->data_buf;
    else {
        error_log(ERROR_MINOR, "Nothing to send, but bu_sendAllChunks was called !");
        return 1;
    }

    if (bu_ptr->sack_in_buffer) {
        rxc_stop_sack_timer();
        /* SACKs by default go to the last active address, from which data arrived */
        send_len = bu_ptr->sack_position; /* at least sizeof(SCTP_common_header) */
        /* at most pointing to the end of SACK chunk */
        event_logi(VVERBOSE, "bu_sendAllChunks(sack) : send_len == %d ", send_len);
        if (bu_ptr->ctrl_chunk_in_buffer) {
            memcpy(&send_buffer[send_len],
                   &(bu_ptr->ctrl_buf[sizeof(SCTP_common_header)]),
                   (bu_ptr->ctrl_position - sizeof(SCTP_common_header)));
            send_len += bu_ptr->ctrl_position - sizeof(SCTP_common_header);
            event_logi(VVERBOSE, "bu_sendAllChunks(sack+ctrl) : send_len == %d ", send_len);
        }
        if (bu_ptr->data_in_buffer) {
            memcpy(&send_buffer[send_len],
                   &(bu_ptr->data_buf[sizeof(SCTP_common_header)]),
                   (bu_ptr->data_position - sizeof(SCTP_common_header)));
            send_len += bu_ptr->data_position - sizeof(SCTP_common_header);
            event_logi(VVERBOSE, "bu_sendAllChunks(sack+data) : send_len == %d ", send_len);
        }
    } else if (bu_ptr->ctrl_chunk_in_buffer) {
        send_len = bu_ptr->ctrl_position;
        event_logi(VVERBOSE, "bu_sendAllChunks(ctrl) : send_len == %d ", send_len);
        if (bu_ptr->data_in_buffer) {
            memcpy(&send_buffer[send_len],
                   &(bu_ptr->data_buf[sizeof(SCTP_common_header)]),
                   (bu_ptr->data_position - sizeof(SCTP_common_header)));
            send_len += bu_ptr->data_position - sizeof(SCTP_common_header);
            event_logi(VVERBOSE, "bu_sendAllChunks(ctrl+data) : send_len == %d ", send_len);
        }

    } else if (bu_ptr->data_in_buffer) send_len = bu_ptr->data_position;

    event_logi(VVERBOSE, "bu_sendAllChunks(finally) : send_len == %d ", send_len);

    if (send_len > 1480) {
        fprintf(stderr, "MTU definitely exceeded (%u) - aborting\n",send_len);
        fprintf(stderr, "sack_position: %u, ctrl_position: %u, data_position: %u\n",
            bu_ptr->sack_position,bu_ptr->ctrl_position,bu_ptr->data_position);
        abort();
    }

    if ((bu_ptr->data_in_buffer) && (idx != -1)) pm_chunksSentOn(idx);

    event_logii(VERBOSE, "bu_sendAllChunks() : sending message len==%u to adress idx=%d", send_len, idx);

    result = mdi_send_message((SCTP_message *) send_buffer, send_len, idx);

    event_logi(VVERBOSE, "bu_sendAllChunks(): result == %s ", (result==0)?"OKAY":"ERROR");

    /* reset all positions */
    bu_ptr->sack_in_buffer = FALSE;
    bu_ptr->ctrl_chunk_in_buffer = FALSE;
    bu_ptr->data_in_buffer = FALSE;
    bu_ptr->got_send_request = FALSE;
    bu_ptr->got_send_address = FALSE;

    bu_ptr->data_position = sizeof(SCTP_common_header);
    bu_ptr->ctrl_position = sizeof(SCTP_common_header);
    bu_ptr->sack_position = sizeof(SCTP_common_header);

    return result;
}
Exemple #10
0
/*
 * rbu_findAddress: looks for address type parameters in INIT or INIT-ACKs
 * All parameters within the chunk are looked at, and the n-th supported address is
 * copied into the provided buffer pointed to by the foundAddress parameter.
 * If there are less than n addresses, an appropriate error is
 * returned. n should be at least 1, of course.
 * @param  chunk            pointer to an INIT or INIT ACK chunk
 * @param  n                get the n-th address
 * @param  foundAddress     pointer to a buffer where an address, if found, will be copied
 * @return -1  for parameter problem, 0 for success (i.e. address found), 1 if there are not
 *             that many addresses in the chunk.
 */
gint rbu_findAddress(guchar * chunk, guint n, union sockunion* foundAddress, int supportedAddressTypes)
{
    gushort processed_len;
    guint len = 0, parameterLength = 0;
    guchar *current_position;
    guint pad_bytes;
    SCTP_init *initChunk;
    SCTP_vlparam_header* vlp;
    SCTP_ip_address * address;
    unsigned int foundAddressNumber = 0;

    initChunk = (SCTP_init *) chunk;
    if (foundAddress == NULL || n < 1 || n > SCTP_MAX_NUM_ADDRESSES)
        return -1;
    if (initChunk->chunk_header.chunk_id != CHUNK_INIT &&
        initChunk->chunk_header.chunk_id != CHUNK_INIT_ACK) {
        return -1;
    }
    len = ntohs(initChunk->chunk_header.chunk_length);
    current_position = initChunk->variableParams;
    processed_len = (sizeof(SCTP_chunk_header)+sizeof(SCTP_init_fixed));

    while (processed_len < len) {
        event_logii(INTERNAL_EVENT_0,
                    "rbu_findAddress : len==%u, processed_len == %u", len, processed_len);
        vlp = (SCTP_vlparam_header*) current_position;
        parameterLength = ntohs(vlp->param_length);

        if (parameterLength < 4 || parameterLength + processed_len > len) return -1;

        if (ntohs(vlp->param_type) == VLPARAM_IPV4_ADDRESS &&
            supportedAddressTypes & SUPPORT_ADDRESS_TYPE_IPV4) {
            /* discard invalid addresses */
            foundAddressNumber++;
            if (foundAddressNumber == n) {
                address = (SCTP_ip_address *)current_position;
                /* copy the address over to the user buffer */
                foundAddress->sa.sa_family = AF_INET;
                foundAddress->sin.sin_port = 0;
                foundAddress->sin.sin_addr.s_addr = address->dest_addr.sctp_ipv4;
                return 0;
            }
#ifdef HAVE_IPV6
        } else if (ntohs(vlp->param_type) == VLPARAM_IPV6_ADDRESS &&
            supportedAddressTypes & SUPPORT_ADDRESS_TYPE_IPV6) {
            /* discard invalid addresses */
            foundAddressNumber++;
            if (foundAddressNumber == n) {
                address = (SCTP_ip_address *)current_position;
                /* copy the address over to the user buffer */
                foundAddress->sa.sa_family = AF_INET6;
                foundAddress->sin6.sin6_port = htons(0);
                foundAddress->sin6.sin6_flowinfo = htonl(0);
#ifdef HAVE_SIN6_SCOPE_ID
                foundAddress->sin6.sin6_scope_id = htonl(0);
#endif
                memcpy(foundAddress->sin6.sin6_addr.s6_addr,
                       address->dest_addr.sctp_ipv6, sizeof(struct in6_addr));

                return 0;
            }
#endif
        }
        processed_len += parameterLength;
        pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
        processed_len += pad_bytes;
        current_position += (parameterLength + pad_bytes * sizeof(unsigned char));
    }
    return 1;
}