Beispiel #1
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);

}
/**
 * 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)
{
    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((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->ctrl_buf[bu_ptr->ctrl_position]), chunk,
           CHUNKP_LENGTH((SCTP_chunk_header *) chunk));
    bu_ptr->ctrl_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->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((SCTP_chunk_header *) 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)
{
    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((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;
    }

    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((SCTP_chunk_header *) chunk));
    bu_ptr->sack_position += CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
    bu_ptr->sack_in_buffer = TRUE;

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

    /* SACK always multiple of 32 bytes, do not care about padding */
    return 0;
}
Beispiel #4
0
/**
 * 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;

}
/**
 * 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)
{
  gint result;
  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((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->data_buf[bu_ptr->data_position]), chunk,
          CHUNKP_LENGTH((chunk_fixed_t * ) chunk));
  bu_ptr->data_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->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((chunk_fixed_t *) 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;
}