コード例 #1
0
ファイル: rbundling.c プロジェクト: thilinamh/sctplib
/**
 * 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;
}
コード例 #2
0
/**
 * 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;
}
コード例 #3
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;
}
コード例 #4
0
gboolean bu_userDataOutbound(void)
{
    bundling_instance *bu_ptr;

    bu_ptr = (bundling_instance *) mdi_readBundling();
    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Setting global bundling buffer ");
        bu_ptr = global_buffer;
    }
    event_logi(VERBOSE, "bu_userDataOutbound() was called... and is %s ",(bu_ptr->data_in_buffer==TRUE)?"TRUE":"FALSE");
    return bu_ptr->data_in_buffer;
}
コード例 #5
0
/**
 * 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;
}
コード例 #6
0
/**
 * Enable sending again - wait after received chunks have
 * been diassembled completely.
 */
void bu_unlock_sender(guint* ad_idx)
{
    bundling_instance *bu_ptr;

    bu_ptr = (bundling_instance *) mdi_readBundling();
    if (!bu_ptr) {              /* Assume that no association exists, so we take the global bundling buffer */
        event_log(VERBOSE, "Setting global bundling buffer ");
        bu_ptr = global_buffer;
    }
    bu_ptr->locked = FALSE;
    event_logi(VERBOSE, "bu_unlock_sender() was called..and got %s send request -> processing",
       (bu_ptr->got_send_request == TRUE)?"A":"NO");

    if (bu_ptr->got_send_request == TRUE) bu_sendAllChunks(ad_idx);

}
コード例 #7
0
/**
 * 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;
}
コード例 #8
0
ファイル: rbundling.c プロジェクト: thilinamh/sctplib
/**
 * Disassembles chunks from a received datagram
 *
 * FIXME : data chunks may only be parsed after control chunks.....
 *
 * All chunks within the datagram are dispatched and sent to the appropriate
 * module, i.e.: control chunks are sent to sctp_control/pathmanagement,
 * SACK chunks to reliable_transfer, and data_chunks to RX_control.
 * Those modules must get a pointer to the start of a chunk and
 * information about its size (without padding).
 * @param  address_index  index of address on which this data arrived
 * @param  datagram     pointer to first chunk of the newly received data
 * @param  len          length of payload (i.e. len of the concatenation of chunks)
 */
gint rbu_rcvDatagram(guint address_index, guchar * datagram, guint len)
{
    /* sctp common header header has been verified */
    /* tag (if association is established) and CRC is okay */
    /* get first chunk-id and length, pass pointers & len on to relevant module :
       - CHUNK_INIT, CHUNK_INIT_ACK,CHUNK_ABORT, CHUNK_SHUTDOWN,CHUNK_SHUTDOWN_ACK
       CHUNK_COOKIE_ECHO,CHUNK_COOKIE_ACK go to SCTP_CONTROL (change of association state)
       - CHUNK_HBREQ, CHUNK_HBACK go to PATH_MAN instance
       - CHUNK_SACK goes to RELIABLE_TRANSFER
       - CHUNK_ERROR probably to SCTP_CONTROL as well  (at least there !)
       - CHUNK_DATA goes to RX_CONTROL
     */
    guchar *current_position;
    gushort processed_len = 0, chunk_len;
    gushort pad_bytes;
    SCTP_simple_chunk *chunk;
    gboolean data_chunk_received = FALSE;

    int association_state = STATE_OK;
    gboolean send_it = FALSE;

    bu_lock_sender();

    current_position = datagram; /* points to the first chunk in this pdu */
    event_log(INTERNAL_EVENT_0, "Entered rbu_rcvDatagram()...... ");
    /* CHECKME : beim Empfangen leerer Chunks tritt im Bundling eine Endlosschleife auf ??? */
    while (processed_len < len) {

        chunk = (SCTP_simple_chunk *) current_position;
        chunk_len = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
        event_logiiii(INTERNAL_EVENT_0,
                     "rbu_rcvDatagram(address=%u) : len==%u, processed_len = %u, chunk_len=%u",
                     address_index, len, processed_len, chunk_len);
        if ((processed_len+chunk_len) > len || chunk_len < 4) {
            error_logiii(ERROR_MINOR, "Faulty chunklen=%u, total len=%u,processed_len=%u --> dropping packet  !",
                                    chunk_len,len,processed_len);
            /* if the association has already been removed, we cannot unlock it anymore */
            bu_unlock_sender(&address_index);
            return 1;
        }
        /*
         * TODO :   Add return values to the chunk-functions, where they can indicate what
         *          to do with the rest of the datagram (i.e. DISCARD after stale COOKIE_ECHO
         *          with tie tags that do not match the current ones)
         */
        switch (chunk->chunk_header.chunk_id) {
        case CHUNK_DATA:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received DATA chunk");
            rxc_data_chunk_rx((SCTP_data_chunk*) chunk, address_index);
            data_chunk_received = TRUE;
            break;
        case CHUNK_INIT:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received INIT chunk");
            association_state = sctlr_init((SCTP_init *) chunk);
            break;
        case CHUNK_INIT_ACK:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received INIT ACK chunk");
            association_state = sctlr_initAck((SCTP_init *) chunk);
            break;
        case CHUNK_SACK:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received SACK chunk");
            rtx_process_sack(address_index, chunk, len);
            break;
        case CHUNK_HBREQ:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received HB_REQ chunk");
            pm_heartbeat((SCTP_heartbeat *) chunk, address_index);
            break;
        case CHUNK_HBACK:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received HB_ACK chunk");
            pm_heartbeatAck((SCTP_heartbeat *) chunk);
            break;
        case CHUNK_ABORT:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received ABORT chunk");
            association_state = sctlr_abort();
            break;
        case CHUNK_SHUTDOWN:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received SHUTDOWN chunk");
            association_state = sctlr_shutdown((SCTP_simple_chunk *) chunk);
            break;
        case CHUNK_SHUTDOWN_ACK:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received SHUTDOWN ACK chunk");
            association_state = sctlr_shutdownAck();
            break;
        case CHUNK_ERROR:
            event_log(INTERNAL_EVENT_0, "Error Chunk");
            eh_recv_chunk(chunk);
            break;
        case CHUNK_COOKIE_ECHO:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received COOKIE ECHO chunk");
            sctlr_cookie_echo((SCTP_cookie_echo *) chunk);
            break;
        case CHUNK_COOKIE_ACK:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received COOKIE ACK chunk");
            sctlr_cookieAck((SCTP_simple_chunk *) chunk);
            break;
     /* case CHUNK_ECNE:
        case CHUNK_CWR:
            event_logi(INTERNAL_EVENT_0,
                       "Chunktype %u not Supported Yet !!!!!!!!", chunk->chunk_header.chunk_id);
            break;*/
        case CHUNK_SHUTDOWN_COMPLETE:
            event_log(INTERNAL_EVENT_0, "*******************  Bundling received SHUTDOWN_COMPLETE chunk");
            association_state = sctlr_shutdownComplete();
            break;
        case CHUNK_FORWARD_TSN:
            if (mdi_supportsPRSCTP() == TRUE) {
                event_log(INTERNAL_EVENT_0, "*******************  Bundling received FORWARD_TSN chunk");
                rxc_process_forward_tsn((SCTP_simple_chunk *) chunk);
                break;
            } else
                continue;
    /*    case CHUNK_ASCONF: */
            /* check that ASCONF chunks are standalone chunks, not bundled with any other
               chunks. Else ignore the ASCONF chunk (but not the others) */
/*            event_log(INTERNAL_EVENT_0, "Bundling received ASCONF chunk");
            asc_recv_asconf_chunk((SCTP_simple_chunk *) chunk);
            break;
        case CHUNK_ASCONF_ACK:
            event_log(INTERNAL_EVENT_0, "Bundling received ASCONF_ACK chunk");
            asc_recv_asconf_ack((SCTP_simple_chunk *) chunk);
            break; */
        default:
        /* 00 - Stop processing this SCTP packet and discard it, do not process
                any further chunks within it.
           01 - Stop processing this SCTP packet and discard it, do not process
                any further chunks within it, and report the unrecognized
                parameter in an 'Unrecognized Parameter Type' (in either an
                ERROR or in the INIT ACK).
           10 - Skip this chunk and continue processing.
           11 - Skip this chunk and continue processing, but report in an ERROR
                Chunk using the 'Unrecognized Chunk Type' cause of error. */
            if ((chunk->chunk_header.chunk_id & 0xC0) == 0x0) {            /* 00 */
                processed_len = len;
                event_logi(EXTERNAL_EVENT_X, "00: Unknown chunktype %u in rbundling.c", chunk->chunk_header.chunk_id);
            } else if ((chunk->chunk_header.chunk_id & 0xC0) == 0x40) {    /* 01 */
                processed_len = len;
                eh_send_unrecognized_chunktype((unsigned char*)chunk,chunk_len);
                event_logi(EXTERNAL_EVENT_X, "01: Unknown chunktype %u in rbundling.c",chunk->chunk_header.chunk_id);
            } else if ((chunk->chunk_header.chunk_id & 0xC0) == 0x80) {    /* 10 */
                /* nothing */
                event_logi(EXTERNAL_EVENT_X, "10: Unknown chunktype %u in rbundling.c",chunk->chunk_header.chunk_id);
            } else if ((chunk->chunk_header.chunk_id & 0xC0) == 0xC0) {    /* 11 */
                event_logi(EXTERNAL_EVENT_X, "11: Unknown chunktype %u in rbundling.c", chunk->chunk_header.chunk_id);
                eh_send_unrecognized_chunktype((unsigned char*)chunk,chunk_len);
            }
            break;
        }

        processed_len += chunk_len;
        pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
        processed_len += pad_bytes;
        current_position += (chunk_len + pad_bytes) * sizeof(unsigned char);

        if (association_state != STATE_OK) processed_len = len;

        event_logiiii(VVERBOSE, "processed_len=%u, pad_bytes=%u, current_position=%u, chunk_len=%u",
            processed_len, pad_bytes, current_position,chunk_len);
    }

    if (association_state != STATE_STOP_PARSING_REMOVED) {

        if (data_chunk_received == TRUE) {
            /* update SACK structure and start SACK timer */
            rxc_all_chunks_processed(TRUE);
        } else {
            /* update SACK structure and datagram counter */
            rxc_all_chunks_processed(FALSE);
        }
        /* optionally also add a SACK chunk, at least for every second datagram
         * see section 6.2, second paragraph
         */
        if (data_chunk_received == TRUE){
            send_it = rxc_create_sack(&address_index, FALSE);
            se_doNotifications();
            if (send_it==TRUE) bu_sendAllChunks(&address_index);
        }
        /* if the association has already been removed, we cannot unlock it anymore */
        bu_unlock_sender(&address_index);
    }

    return 0;

}