/*
 * Copyright 2018, 2019 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "usb_host_config.h"
#if ((defined USB_HOST_CONFIG_CDC_RNDIS) && (USB_HOST_CONFIG_CDC_RNDIS))
#include "usb_host.h"
#include "usb_host_cdc.h"
#include "usb_host_cdc_rndis.h"

#include "usb_host_devices.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/
/*A value, generated by the host, used to match the host's sent request to the response
from the device. It is the responsibility of the host to ensure the uniqueness of this
value among all outstanding request messages sent to the device. */
static uint32_t messageID = 1U;
/*******************************************************************************
 * Code
 ******************************************************************************/
usb_status_t USB_HostRndisInitMsg(usb_host_class_handle classHandle,
                                  uint8_t *messageBuffer,
                                  uint32_t messageBufferLength,
                                  transfer_callback_t callbackFn,
                                  void *callbackParam)
{
    void *temp = (void *)messageBuffer;

    rndis_init_msg_struct_t *message = (rndis_init_msg_struct_t *)temp;

    message->messageType     = REMOTE_NDIS_INITIALIZE_MSG;
    message->messageLength   = sizeof(rndis_init_msg_struct_t);
    messageID                = messageID % 1024U;
    message->requestID       = messageID++;
    message->majorVersion    = RNDIS_MAJOR_VERSION;
    message->minorVersion    = RNDIS_MINOR_VERSION;
    message->maxTransferSize = RNDIS_MAX_TRANSFER_PACKET_SIZE;

    return USB_HostCdcSendEncapsulatedCommand(classHandle, messageBuffer, (uint16_t)message->messageLength, callbackFn,
                                              callbackParam);
}

usb_status_t USB_HostRndisQueryMsg(usb_host_class_handle classHandle,
                                   uint32_t Oid,
                                   uint8_t *messageBuffer,
                                   uint32_t messageBufferLength,
                                   uint32_t informationOffset,
                                   uint32_t informationLength,
                                   uint8_t *OIDInputBuffer,
                                   transfer_callback_t callbackFn,
                                   void *callbackParam)
{
    void *temp                        = (void *)messageBuffer;
    rndis_query_msg_struct_t *message = (rndis_query_msg_struct_t *)temp;

    message->messageType             = REMOTE_NDIS_QUERY_MSG;
    message->messageLength           = sizeof(rndis_query_msg_struct_t) + informationLength;
    messageID                        = messageID % 1024U;
    message->requestID               = messageID++;
    message->oid                     = Oid;
    message->informationBufferLength = informationLength;
    message->informationBufferOffset = informationOffset;
    message->deviceVcHandle          = 0U;
    if (0U != informationLength)
    {
        if (informationLength > (messageBufferLength - RNDIS_QUERY_MSG_SIZE))
        {
#ifdef HOST_ECHO
            usb_echo("buffer is not enough\r\n");
#endif
            message->messageLength           = messageBufferLength;
            message->informationBufferLength = (messageBufferLength - RNDIS_QUERY_MSG_SIZE);
        }
        /*fixed misra 18.1*/
        temp = (void *)(messageBuffer + sizeof(rndis_query_msg_struct_t));
        (void)memcpy(temp, (void *)OIDInputBuffer, message->informationBufferLength);
    }

    return USB_HostCdcSendEncapsulatedCommand(classHandle, messageBuffer, (uint16_t)message->messageLength, callbackFn,
                                              callbackParam);
}
usb_status_t USB_HostRndisHaltMsg(usb_host_class_handle classHandle,
                                  uint8_t *messageBuffer,
                                  uint32_t messageBufferLength,
                                  transfer_callback_t callbackFn,
                                  void *callbackParam)
{
    void *temp                       = (void *)messageBuffer;
    rndis_halt_msg_struct_t *message = (rndis_halt_msg_struct_t *)temp;

    message->messageType   = REMOTE_NDIS_HALT_MSG;
    message->messageLength = sizeof(rndis_halt_msg_struct_t);
    messageID              = messageID % 1024U;
    message->requestID     = messageID++;

    return USB_HostCdcSendEncapsulatedCommand(classHandle, NULL, 0U, callbackFn, callbackParam);
}
usb_status_t USB_HostRndisSetMsg(usb_host_class_handle classHandle,
                                 uint32_t Oid,
                                 uint8_t *messageBuffer,
                                 uint32_t messageBufferLength,
                                 uint32_t informationOffset,
                                 uint32_t informationLength,
                                 uint32_t *OIDInputBuffer,
                                 transfer_callback_t callbackFn,
                                 void *callbackParam)

{
    void *temp                      = (void *)messageBuffer;
    rndis_set_msg_struct_t *message = (rndis_set_msg_struct_t *)temp;

    message->messageType             = REMOTE_NDIS_SET_MSG;
    message->messageLength           = sizeof(rndis_set_msg_struct_t) + informationLength;
    messageID                        = messageID % 1024U;
    message->requestID               = messageID++;
    message->oid                     = Oid;
    message->informationBufferLength = informationLength;
    message->informationBufferOffset = informationOffset;
    message->deviceVcHandle          = 0U;
    if (0U != informationLength)
    {
        if (informationLength > (messageBufferLength - RNDIS_SET_MSG_SIZE))
        {
#ifdef HOST_ECHO
            usb_echo("buffer is not enough\r\n");
#endif
            message->informationBufferLength = messageBufferLength - RNDIS_SET_MSG_SIZE;
        }
        /*fixed misra 18.1*/
        temp = (void *)(messageBuffer + sizeof(rndis_set_msg_struct_t));
        (void)memcpy((temp), (void *)OIDInputBuffer, message->informationBufferLength);
    }
    return USB_HostCdcSendEncapsulatedCommand(classHandle, messageBuffer, (uint16_t)message->messageLength, callbackFn,
                                              callbackParam);
}
usb_status_t USB_HostRndisResetMsg(usb_host_class_handle classHandle,
                                   uint8_t *messageBuffer,
                                   uint32_t messageBufferLength,
                                   transfer_callback_t callbackFn,
                                   void *callbackParam)
{
    void *temp                        = (void *)messageBuffer;
    rndis_reset_msg_struct_t *message = (rndis_reset_msg_struct_t *)temp;

    message->messageType   = REMOTE_NDIS_QUERY_MSG;
    message->messageLength = sizeof(rndis_reset_msg_struct_t);
    message->Reserved      = 0U;

    return USB_HostCdcSendEncapsulatedCommand(classHandle, NULL, 0U, callbackFn, callbackParam);
}
usb_status_t USB_HostRndisSendDataMsg(usb_host_class_handle classHandle,
                                      uint8_t *messageBuffer,
                                      uint32_t messageBufferLength,
                                      uint32_t oobDataOffset,
                                      uint32_t oobDataLength,
                                      uint32_t numOOBDataElements,
                                      uint32_t perPacketInfoOffset,
                                      uint32_t perPacketInfoLength,
                                      uint8_t *dataBuffer,
                                      uint32_t dataLength,
                                      transfer_callback_t callbackFn,
                                      void *callbackParam)
{
    void *temp                         = (void *)messageBuffer;
    rndis_packet_msg_struct_t *message = (rndis_packet_msg_struct_t *)temp;

    message->messageType   = REMOTE_NDIS_PACKET_MSG;
    message->messageLength = dataLength + RNDIS_DAT_MSG_HEADER_SIZE;

    message->dataOffset          = 36U;
    message->dataLength          = dataLength;
    message->oobDataOffset       = oobDataOffset;
    message->oobDataLength       = oobDataLength;
    message->numOOBDataElements  = numOOBDataElements;
    message->perPacketInfoOffset = perPacketInfoOffset;
    message->perPacketInfoLength = perPacketInfoLength;
    message->vcHandle            = 0U;
    message->reserved            = 0U;
    if (dataLength > RNDIS_FRAME_MAX_FRAMELEN)
    {
#ifdef HOST_ECHO
        usb_echo("buffer is not enough\r\n");
#endif
        message->dataLength = RNDIS_FRAME_MAX_FRAMELEN;
    }
    temp = (void *)&message->dataBuffer[0];
    (void)memcpy(temp, (void *)dataBuffer, message->dataLength);

    return USB_HostCdcDataSend(classHandle, messageBuffer, message->messageLength, callbackFn, callbackParam);
}
usb_status_t USB_HostRndisRecvDataMsg(usb_host_class_handle classHandle,
                                      uint8_t *buffer,
                                      uint32_t bufferLength,
                                      transfer_callback_t callbackFn,
                                      void *callbackParam)
{
    return USB_HostCdcDataRecv(classHandle, buffer, bufferLength, callbackFn, callbackParam);
}

#endif
