/*****************************************************************************
* Copyright (c) 2006 Digi International Inc., All Rights Reserved
* 
* This software contains proprietary and confidential information of Digi
* International Inc.  By accepting transfer of this copy, Recipient agrees
* to retain this software in confidence, to prevent disclosure to others,
* and to make no use of this software other than that for which it was
* delivered.  This is an unpublished copyrighted work of Digi International
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
* prohibited.
* 
* Restricted Rights Legend
*
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
* Technical Data and Computer Software clause at DFARS 252.227-7031 or
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -
* Restricted Rights at 48 CFR 52.227-19, as applicable.
*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
*
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "naeth.h"
#include "eth.h"
#include "nammu.h"
#include "tx_api.h"
#include <trbypass.h>
#if	BSP_ETH_WIFI_BRIDGE
#include "ewb_api.h"
#endif

/*ad*
 * The Ethernet API is used to register protocol stacks with the Ethernet
 * driver, and to transmit packets.  Protocol stacks are registered with
 * the @link NAEthAddPacketType function.  This function specifies an Ethernet
 * frame type, protocol ID, and a function to receive packets.  All packets
 * with the matching frame type and protocol ID are passed to the protocol
 * stack after the function completes.
 *
 * Packet filters can also be specified when a protocol stack is registered.
 * Packet filters specify additional criteria for incoming packets.  Packets 
 * that match these criteria are discarded even if they are addressed to a
 * registered protocol stack.  This feature is usually used to filter out
 * unwanted broadcast and multicast packets.
 *
 * The API also has functions to transmit raw Ethernet packets.
 *
 * The Ethernet bypass API allows to register a raw receive filter function, to 
 * give higher priority to received non-TCP/IP packets. On transmit it allows 
 * to reuse transmitted packets, to send packets using an external buffer. 
 *
 * @category BSP:Device_Drivers:EthernetDriver
 * @since 6.0
 * @overview Ethernet Driver
 * @platform All_Eth_Platforms
 * @include "eth_api.h"
 * @library bsp
 * @external
 *ad*/

/*ad*
 * The Ethernet bypass API allows a caller to register a raw receive filter function,
 * and to give higher priority to received non-TCP/IP packets. On transmit it allows 
 * the system to reuse transmitted packets, or to send packets using an external buffer. 
 *
 * Set @link BSP_USE_ETHERNET_RECV_QUEUE to TRUE in bsp_net.h to queue received TCP/IP packets.
 * You can change the priority of the thread that passes packets to the TCP/IP stack.
 *
 * On transmit, bypass packets use a queue, separate from the TCP/IP stack, and a 
 * designated number of DMA buffer descriptors. @link BSP_ENABLE_ETHERNET_BYPASS must be 
 * enabled in bsp_net.h to use @link naEthBypassTransmit. The @link BSP_ETHERNET_BYPASS_SEND_BUFFERS 
 * constant specifies the number of bypass send DMA buffer descriptors.
 *
 * Set @link BSP_ENABLE_ETHERNET_INTERRUPT_FILTER to TRUE in bsp_net.h to process some received 
 * packets directly in the context of the Ethernet receive interrupt. A packet can be send from 
 * Ethernet receive ISR using @link naEthBypassTransmit routine. In this mode a received packet can't
 * be reused for transmit.
 *
 * @category BSP:Device_Drivers:EthernetDriver:EthernetBypass
 * @since 6.3
 * @overview Ethernet Bypass
 * @include "eth_api.h"
 * @library bsp
 * @platform All_Eth_Platforms
 * @external
 *ad*/

#ifdef ETH_API_ENABLED

#define ETHERNET_II_TYPE_OFFSET 12
#define MIN_9750_PACKET_SIZE    34
#define ETH_HEADER_LEN          14

static ethCustomFilterFnType   customFilterFn;
static ethReceiveFnType        customRecvFn;
#if BSP_ENABLE_ETHERNET_INTERRUPT_FILTER
static ethCustomFilterFnType   isrFilterFn;
#endif

#if (BSP_ENABLE_ETHERNET_BYPASS || BSP_USE_ETHERNET_RECV_QUEUE)
#define ETH_USE_QUEUE
#define THREAD_STACK_SIZE 4096
#endif


#if BSP_ENABLE_ETHERNET_BYPASS
#define BYPASS_SEND_COMLPETE_TASK_PRI 4

typedef struct 
{
    tfBypassQueue     eth_sendq;
    volatile unsigned completed_cnt;
    volatile unsigned submitted_cnt;
    TX_THREAD         tcb;
    TX_EVENT_FLAGS_GROUP events;

} txBypassDataType;

static txBypassDataType *txBypassData;
#endif

typedef struct
{
    char         *buffer;
    unsigned     size;
    ethReceiveFnType recvFn;

#if BSP_USE_ETHERNET_RECV_QUEUE
    tfBypassQueue  eth_recvq;
    TX_THREAD      tcb;
    TX_EVENT_FLAGS_GROUP events;
#endif
} rxBypassDataType;

static rxBypassDataType *rxBypassData;


#if BSP_ENABLE_ETHERNET_PACKET_TYPES == TRUE
#define MAX_PACKET_TYPES        10
#define DONT_CARE               0
#define IP_FRAME_TYPE           0x800
#define ARP_FRAME_TYPE          0x806
#define RARP_FRAME_TYPE         0x8035

#ifdef PPPOE_PROTOCOL
#define PPPOE_DIS_FRAME_TYPE    0x8863
#define PPPOE_SES_FRAME_TYPE    0x8864
#endif
#define UDP_PACKET_TYPE         0x11
#define IP_PACKET_TYPE_OFFSET   23


static ethPacketType packetType[MAX_PACKET_TYPES];
static unsigned int packetTypeCount = 0;
static ethReceiveFnType unclaimedPacketFn = NULL;


/*ad*
 * This structure defines the IP packet type.  It includes a filter for UDP
 * broadcast packets.  By default, the filter is disabled.  The function
 * @link NABlockUDPBroadcasts enables the filter by setting the filterCount
 * field to 1.
 *
 * @category BSP:Device_Drivers:EthernetDriver 
 * @since 6.0
*ad*/
static ethPacketType ipPacketType =
{
    ethEthernetII,
    IP_FRAME_TYPE,
    /* NULL pointer is used to pass packets to Treck TCP/IP stack */
    NULL,   
    {
        {
            /*
             * This filter blocks UDP broadcast packets.
             */
            {
                {
                    {UDP_PACKET_TYPE},
                    1,
                    IP_PACKET_TYPE_OFFSET,
                    FALSE
                }
            },
            1,
            FALSE,
            TRUE
        }
    },
    /*
     * This is the filter count.  NABlockUDPBroadcasts will set it
     * to 1 to enable UDP broadcast filtering.
     */
    0,
    FALSE      /* 2nd CRC check is not usually required on IP packets*/
};

/*
 * Defines the ARP packet type
 *
 */
static ethPacketType arpPacketType =
{
    ethEthernetII,
    ARP_FRAME_TYPE,
    NULL,    /* NULL pointer is used to pass packets to Treck TCP/IP stack */
    /*
     * The rest of this initializer is here just to prevent the compiler
     * from generating a warning.  It would normally setup a filter for
     * this particular packet type, which we are not interested in doing.
     */
    {
        {
            {
                {
                    {0},
                    0,
                    0,
                    FALSE
                }
            },
            0,
            FALSE,
            FALSE
        }
    },
    0,
    FALSE      /* 2nd CRC check is not usually required on IP packets*/
};



/*
 * This structure defines the RARP packet type.  
 *
 */
static ethPacketType rarpPacketType =
{
    ethEthernetII,
    RARP_FRAME_TYPE,
    NULL,    /* NULL pointer is used to pass packets to Treck TCP/IP stack */
    /*
     * The rest of this initializer is here just to prevent the compiler
     * from generating a warning.  It would normally setup a filter for
     * this particular packet type, which we are not interested in doing.
     */
    {
        {
            {
                {
                    {0},
                    0,
                    0,
                    FALSE
                }
            },
            0,
            FALSE,
            FALSE
        }
    },
    0,
    FALSE      /* 2nd CRC check is not usually required on IP packets*/
};
#endif

/*ad*
 * Allocates a network message
 *
 * This routine allocates an network message. The size of the data 
 * buffer is determined by the value of the length parameter.  
 * The message can be freed by calling @link naNetMsgFree.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 7.0
 *
 * @note    This function replaces NAEthMsgAllocate.   
 *
 * @param length    length of buffer to allocate, might be 0.
 *
 * @return NULL         The function failed and has not allocated the buffer.
 * @return otherwise    Network message handle.
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:naNetMsgPtr
 *
*ad*/
naNetMsgPtr naNetMsgAllocate(unsigned length)
{
    ttUserBuffer msg_handle = NULL;

#if	BSP_ETH_WIFI_BRIDGE
    bfGetDriverBuffer(&msg_handle, length, 4);
#else
    tfGetDriverBuffer(&msg_handle, length, 4);
#endif
    if (msg_handle && length == 0)
    {
        tfStoreBypassPacketDataPtr((ttPacketPtr) msg_handle, NULL, 0);
    }

    return (naNetMsgPtr) msg_handle;
}

/*ad*
 * Frees a message allocated by @link naNetMsgAllocate
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 7.0
 *
 * @note    This function replaces NAEthMsgFree.   
 *
 * @param msg_handle   Network message handle.
 *
*ad*/
void naNetMsgFree(naNetMsgPtr msg_handle)
{
    ttPacketPtr packet = (ttPacketPtr) msg_handle;
    if (packet)
    {
        tfSetBypassPacketUserCallback(packet, NULL);
        tfFreeDriverBuffer(&packet->pktUserStruct);
    }
}

/*ad*
 * Provides an access to the native data buffer of the network message
 *
 * This is a non-blocking function. If the message was allocated with 0 length, 
 * the data buffer pointer is NULL. An external buffer must be attached to this 
 * message to transmit data.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 7.0
 *
 * @param msg_handle   Network message handle.
 * @param buffer_ptr   To be filled in with the pointer to the data buffer.
 * @param length       To be filled in with the size to the data buffer.
 *
 * @return ETH_FAILURE  Bad arguments.
 * @return ETH_SUCCESS  The length and buffer_ptr arguments are filled in with a 
 *                      the data buffer size and pointer to the data buffer.
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:naNetMsgGetDataPtr
 * @see @link BSP:Device_Drivers:EthernetDriver:naNetMsgStoreDataPtr
*ad*/
int naNetMsgGetDataBufferPtr(naNetMsgPtr msg_handle, char ** buffer_ptr, unsigned * length)
{
    return tfGetBypassPacketDataBufferPtr((ttPacketPtr) msg_handle, buffer_ptr, length) 
                                    == TM_DEV_OKAY ? ETH_SUCCESS : ETH_FAILURE;
}

/*ad*
 * Provides an access to the data and size of the network message.
 *
 * This is a non-blocking function. The message data is formatted as a continuous data buffer 
 * with a valid Ethernet header followed by data. The message data size includes the size
 * of the Ethernet header.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 7.0
 *
 * @param msg_handle   Network message handle.
 * @param data_ptr     To be filled in with the pointer to the message data.
 * @param length       To be filled in with the message size.
 *
 * @return ETH_FAILURE  Bad arguments.
 * @return ETH_SUCCESS  The length and buffer_ptr arguments are filled in with a 
 *                      the data size and pointer to the message data.
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:naNetMsgGetDataBufferPtr
 * @see @link BSP:Device_Drivers:EthernetDriver:naNetMsgStoreDataPtr
*ad*/
int naNetMsgGetDataPtr(naNetMsgPtr msg_handle, char ** data_ptr, unsigned * length)
{
    return tfGetBypassPacketDataPtr((ttPacketPtr) msg_handle, data_ptr, length) 
                                    == TM_DEV_OKAY ? ETH_SUCCESS : ETH_FAILURE;
}

/*ad*
 * Updates the data pointer and size of the network message
 *
 * This is a non-blocking function. The message data is formatted as a continuous data 
 * buffer with a valid Ethernet header followed by data. The message data size includes the size
 * of the Ethernet header.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 7.0
 *
 * @param msg_handle   Network message handle.
 * @param data_ptr     Data pointer.
 * @param length       Data size.
 *
 * @return ETH_FAILURE  Bad arguments.
 * @return ETH_SUCCESS  The data pointer and size of the network message
 *                      have been updated.
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:naNetMsgGetDataBufferPtr
 * @see @link BSP:Device_Drivers:EthernetDriver:naNetMsgGetDataPtr
*ad*/
int naNetMsgStoreDataPtr(naNetMsgPtr msg_handle, char * data_ptr, unsigned length)
{
    return tfStoreBypassPacketDataPtr((ttPacketPtr) msg_handle, data_ptr, length)
                 == TM_DEV_OKAY ? ETH_SUCCESS : ETH_FAILURE;
}


/*ad*
 * Transmits an Ethernet packet 
 *
 * Use this function to transmit a packet allocated by @link naNetMsgAllocate
 * of received by the callback of @link ethReceiveFnType type. 
 *
 * The packet is be placed on the device transmit queue of the TCP/IP stack.  
 * The packet is freed by the TCP/IP stack after the packet has been transmitted. 
 * The packet data must include a valid Ethernet header with the correct 
 * destination and source addresses. 
 *
 * Use @link naNetMsgGetDataPtr, @link naNetMsgGetDataBufferPtr, and @link naNetMsgStoreDataPtr 
 * functions to gain access to the message data and size, data buffer and data buffer size, or 
 * store new data pointer and size.
 *
 * Using this function instead of na_eth_send saves a buffer copy.
 *
 * @note    This function replaces NAEthTransmit. This function must not be used 
 *          to send a packet that has been previously transmitted by 
 *          @link naEthBypassTransmit. This function uses device send queue of the Treck
 *          TCP/IP stack.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver 
 * @since 7.0
 *
 * @param msg_handle  Network message handle. 
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:na_eth_send
 *
 * @return ETH_SUCCESS      Packet has been placed in transmit queue.
 * @return ETH_FAILURE      Bad arguments, or device not open, 
 *
*ad*/
int naEthTransmit(naNetMsgPtr msg_handle)
{
    ttUserInterface interfaceHandle = NULL;
    ttPacketPtr packet = (ttPacketPtr)msg_handle;
    unsigned int multihome = 0;

    int result = ETH_FAILURE;

    if (msg_handle && naIfConfigGetInterfaceHandle("eth0", &interfaceHandle, &multihome) == NASTATUS_SUCCESS)
    {
        char *data_ptr = NULL; 
        unsigned len;

        tfSetBypassPacketDevicePtr(packet, (struct tsDeviceEntry *) interfaceHandle);
        tfSetBypassPacketUserCallback(packet, NULL);
         
        if (tfGetBypassPacketDataPtr(packet, &data_ptr, &len) == ETH_SUCCESS && data_ptr)
        {
            if (tfDeviceSend (packet) == TM_ENOERROR)
                result = ETH_SUCCESS; 
        }
    }
    return result;
}

/*ad*
 * Transmits an Ethernet packet
 *
 * The packet must be formatted as a continuous data buffer 
 * with a valid Ethernet header followed by data.
 * This function allocates an m struct and a new packet buffer.  The packet
 * is copied from the caller's buffer to the newly allocated packet buffer
 * and then placed in the device transmit queue of the TCP/IP stack.  
 * Use @link naEthTransmit to save a buffer copy.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver 
 * @since 5.1
 *
 * @param packet_data       Pointer to buffer containing the packet.
 * @param data_length       Number of bytes in the buffer.
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:naEthTransmit
 *
 * @return ETH_SUCCESS      Packet has been placed in transmit queue.
 * @return ETH_FAILURE      Bad arguments, device not open, 
 *                          or buffer could not be allocated.
*ad*/
int na_eth_send(void * packet_data, unsigned data_length)
{
    char *data_ptr = NULL;
    naNetMsgPtr msg_handle;
    int result = ETH_FAILURE;
    unsigned min_length;

    if (packet_data == NULL || data_length < ETH_HEADER_LEN || data_length > ETH_MAX_PACKET_LENGTH)
        return ETH_FAILURE;
    /*
     * The Ethernet transmitter on the NS9750 and NS9775 may stall if a packet
     * less than 34 bytes is transmitted, so software must pad short packets.
     */
    min_length = (data_length < MIN_9750_PACKET_SIZE) ? 
                          MIN_9750_PACKET_SIZE : data_length;
    

    msg_handle = naNetMsgAllocate(min_length);

    if (msg_handle)
    {
        unsigned len;
        if (tfGetBypassPacketDataPtr((ttPacketPtr) msg_handle, &data_ptr, &len) == ETH_SUCCESS && data_ptr)
        {
            memcpy(data_ptr, packet_data, data_length);
            if (data_length < min_length)
            {
                memset(data_ptr + data_length, 0, min_length - data_length);
            }
            result = naEthTransmit(msg_handle);
        }
        if (result != ETH_SUCCESS)
            naNetMsgFree(msg_handle);
    }
    return result;
}

#if BSP_ENABLE_ETHERNET_PACKET_TYPES == TRUE

int ethAddTcpipPacketTypes(void)
{
    int result = NAEthAddPacketType(&ipPacketType);
    result |= NAEthAddPacketType(&arpPacketType);
    result |= NAEthAddPacketType(&rarpPacketType);
    return result;

}

/*ad*
 * Adds new packet types.
 *
 * This function adds new packet types to the list of packet types supported.
 * This function is typically
 * used to register a new protocol stack with the Ethernet driver.  This function 
 * checks the following before it registers the new packet type:
 *
 *	<list type = "ordered">
 *      <item>The system has not already reached its limit of packet types.</item>
 *      <item>The newPacketType argument is not NULL.</item>
 *      <item>No more than @link ETH_MAX_FILTERS have been specified.</item>
 *      <item>The applyToMulticastOnly and applyToBroadcastOnly flags cannot both be set.
 *            The broadcast address is a multicast address, so set applyToMulticastOnly 
 *            to filter both broadcast and multicast packets.</item>
 *      <item>The filters must be valid.</item>
 *      <item>The Ethernet packet type must not already have been registered.</item>
 *  </list>
 *
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 6.0
 *
 * @param newPacketType     Pointer to @link ethPacketType structure with information that
 *                          identifies the packet type and the protocol receive function.
 *
 * @return ETH_SUCCESS  packet type added
 * @return ETH_FAILURE  unable to add packet type
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:ethPacketType
*ad*/
int NAEthAddPacketType(ethPacketType * newPacketType)
{
    int type_index, matchIndex;
    int result = ETH_FAILURE;
    ttUserInterface interfaceHandle = NULL;
    unsigned int multihome = 0; 
    
    NA_ASSERT(newPacketType != NULL);
    
    if (   (packetTypeCount >= MAX_PACKET_TYPES)
        || (newPacketType == NULL)
        || (newPacketType->filterCount > ETH_MAX_FILTERS)
       )
    {
        goto errExit;
    }
    naIfConfigGetInterfaceHandle("eth0", &interfaceHandle, &multihome);

    for (type_index = 0; type_index < (int) newPacketType->filterCount; type_index++)
    {
        if (newPacketType->filter[type_index].matchCount > ETH_MAX_MATCHES)
        {
            goto errExit;
        }
        if ((newPacketType->filter[type_index].applyToMulticastOnly) && (newPacketType->filter[type_index].applyToBroadcastOnly))
        {
            /*
             * Reject filter if both multicast only and broadcast only are set.  Only one can
             * be set at a time.  The broadcast address is a multicast address, so setting
             * multicast only includes broadcast addresses.
             */
            goto errExit;
        }
        for (matchIndex = 0; matchIndex < newPacketType->filter[type_index].matchCount; matchIndex++)
        {
            if (   (newPacketType->filter[type_index].match[matchIndex].length > ETH_MAX_COMPARE_DATA)
                || (newPacketType->filter[type_index].match[matchIndex].offset >= ETH_MAX_PACKET_LENGTH)
               )
            {
                goto errExit;
            }
        }
    }
    tfBypassLockDevice(interfaceHandle);
/*
 * Make sure the packet type has not already been registered.
 */
    for (type_index = 0; type_index < (int) packetTypeCount; type_index++)
    {
        if (newPacketType->linkProtocolType == packetType[type_index].linkProtocolType)
        {
            switch (newPacketType->linkProtocolType)
            {
                case eth802_2:
                    if (newPacketType->protocolId > ETH_MAX_802_2_DSAP)
                    {
                        tfBypassUnlockDevice(interfaceHandle);
                        goto errExit;
                    }
                    /* Fall through is intended operation*/
                case ethEthernetII:
                case ethSNAP:
                    if (newPacketType->protocolId == packetType[type_index].protocolId)
                    {
                        tfBypassUnlockDevice(interfaceHandle);
                        goto errExit;
                    }
                    break;
                case ethNovell_802_3:
                default:
                    tfBypassUnlockDevice(interfaceHandle);
                    goto errExit;
            }
        }
    }
    
    memcpy (&packetType[packetTypeCount], newPacketType, sizeof (packetType[packetTypeCount]));
    packetTypeCount++;

    tfBypassUnlockDevice(interfaceHandle);
    result = ETH_SUCCESS;
    
    errExit:
    return result;
}

/*ad*
 * Determines whether the packet should be filtered out
 *
 * This routine checks the list of filters 
 * registered with NAEthAddPacketType() and determines whether the packet 
 * matches any of them.  It returns TRUE if the packet matches one of the
 * filters.  Otherwise it returns FALSE.
 *
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 6.0
 *
 * @param packet_type       pointer to structure with information about this packet type
 * @param packet            pointer to packet data buffer
 * @param status            status flags from Ethernet receiver H/W
 * @param length            length of receive packet
 *
 *
 * @return TRUE     Packet matches at least one filter.
 * @return FALSE    Packet does not match any filter.
*ad*/
static BOOLEAN matchesFilter(ethPacketType * packet_type, BYTE * const packet, WORD32 status, unsigned length)
{
    #define ETH_RX_MCAST       0x0800
    #define ETH_RX_BCAST       0x1000
    
    int filterIndex, matchIndex;
    BOOLEAN matches = FALSE;
    
    for (filterIndex = 0; (filterIndex < (int) packet_type->filterCount) && (!matches); filterIndex++)
    {
        ethFilterType *filter = &packet_type->filter[filterIndex];
        
        if (!(filter->applyToBroadcastOnly && (status & ETH_RX_BCAST) == 0) && !(filter->applyToMulticastOnly && (status & ETH_RX_MCAST) == 0))
        {
            BOOLEAN matchesSubfilter = TRUE;
            
            for (matchIndex = 0; (matchIndex < filter->matchCount) && (matchesSubfilter); matchIndex++)
            {
                ethMatchType *pmatch = &filter->match[matchIndex];
                WORD32 address = ((WORD32) packet) + pmatch->offset;
    
                if ((pmatch->offset + pmatch->length) < length)
                {
                /*
                 * Try to avoid a memcmp() since it is probably inefficient.  Only use memcmp() if
                 * we have an alignment problem or we are comparing an unusual number of bytes.
                 */            
                    if (pmatch->length == 1)
                    {
                        matchesSubfilter = (pmatch->compareData[0] == packet[pmatch->offset]) ^ pmatch->wantInverseMatch;
                    }
                    else if ((pmatch->length == 2) && ((address & 1) == 0))
                    {
                        matchesSubfilter = ((*(WORD16 *) &pmatch->compareData[0]) == *(WORD16 *) (packet + pmatch->offset)) ^ pmatch->wantInverseMatch;
                    }
                    else if ((pmatch->length == 4) && ((address & 3) == 0))
                    {
                        matchesSubfilter = ((*(WORD32 *) &pmatch->compareData[0]) == *(WORD32 *) (packet + pmatch->offset)) ^ pmatch->wantInverseMatch;
                    }
                    else
                    {
                        matchesSubfilter = (memcmp(pmatch->compareData, (void *) address, pmatch->length)  == 0) ^ pmatch->wantInverseMatch;
                    }
                }
            }
            matches = matchesSubfilter;
        }
    }
    
    return matches;
}

/*ad*
 * Determines whether the receive packet matches the supplied packet type
 *
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 6.0
 *
 * @param   packet_type  pointer to information about a packet type
 * @param   packet      pointer to packet data
 *
 * @return TRUE     Packet has been passed to a stack.
 * @return FALSE    No stack has registered to receive this packet type.
*ad*/
static BOOLEAN matchesPacketType(ethPacketType * packet_type, BYTE * const packet)
{
    #define NOVELL_CHECKSUM_OFFSET  14
    #define NOVELL_CHECKSUM_VALUE   0xffff
    #define _802_2_DSAP_OFFSET      14
    #define SNAP_DSAP               0xaa
    #define SNAP_ID_OFFSET          20
    
    BOOLEAN result = FALSE;
    
    switch (packet_type->linkProtocolType)
    {
        case ethEthernetII:
            result = (packet_type->protocolId == *(WORD16 *) (packet + ETHERNET_II_TYPE_OFFSET));
            break;
        case ethNovell_802_3:
            if (ETH_MAX_PACKET_LENGTH >= *(WORD16 *) (packet + ETHERNET_II_TYPE_OFFSET))
            {
                result = (NOVELL_CHECKSUM_VALUE == *(WORD16 *) (packet + NOVELL_CHECKSUM_OFFSET));
            }
            break;
        case eth802_2:
            result = (((BYTE) packet_type->protocolId) == *(packet + _802_2_DSAP_OFFSET));
            break;
        case ethSNAP:
            if (SNAP_DSAP == *(packet + _802_2_DSAP_OFFSET))
            {
                /*
                 * The SNAP ID is broken up into two sections.  The first 3 bytes are a vendor
                 * ID, the last 2 bytes are the Ethernet II frame type.  The vendor ID
                 * is usually either set to zero, or to the Ethernet MAC prefix (first 3 bytes of
                 * the Ethernet MAC address) assigned to the manufacturer of the station by
                 * the IEEE.  The vendor ID is therefore useless and can be ignored.
                 * See section 10.5 of IEEE STD 802-2001.
                 */
                result = (packet_type->protocolId == *(packet + SNAP_ID_OFFSET));
            }
            break;
        default:
            break;
    }
    
    return result;
}

/*ad*
 * Registers a function to receive unaccepted packets
 *
 * This function registers a function to receive Ethernet packets that are not accepted
 * by any registered protocol stacks.  Call this function with a NULL pointer to
 * unregister.  
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver  
 * @since 6.0
 *
 * @param recvFn    Pointer to the function that is to receive unclaimed packets.
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:ethReceiveFnType
*ad*/
void NAEthRegisterUnclaimedPacketFn(ethReceiveFnType const recvFn)
{
    ttUserInterface interfaceHandle = NULL;
    unsigned int multihome = 0;

    naIfConfigGetInterfaceHandle("eth0", &interfaceHandle, &multihome);

    tfBypassLockDevice(interfaceHandle);
    unclaimedPacketFn = recvFn;
    tfBypassUnlockDevice(interfaceHandle);
}


/*ad*
 * Controls filter of UDP broadcasts.
 *
 * This function controls whether User Datagram Protocol broadcasts will be 
 * filtered out by the 
 * Ethernet driver.  Filtering can improve performance on networks with lots of
 * broadcast traffic.  However, broadcasts can only be blocked if the IP
 * stack is configured with static parameters as protocols like Dynamic Host
 * Control Protocol (DHCP) require
 * UDP broadcasts.  If the parameter blockUDPBroadcasts is set, the
 * Ethernet driver discards UDP packets addressed to the Ethernet broadcast
 * address.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver 
 * @since 6.0
 *
 * @param blockUDPBroadcasts    Set this parameter to block UDP broadcasts.
*ad*/
void NABlockUDPBroadcasts(BOOLEAN const blockUDPBroadcasts)
{
    if (blockUDPBroadcasts)
    {
        ipPacketType.filterCount = 1;
    }
    else
    {
        ipPacketType.filterCount = 0;
    }
}
#endif


ethFilterActionType naEthKeepThisPacket(char *pktBuffer, unsigned pktlen, WORD32 dma_status)
{
    ethFilterActionType result = ethFilterActionForward;
    
#if (BSP_WANT_2ND_ETHERNET_CHECKSUM && ((PROCESSOR == ns7520) || (PROCESSOR == net50)))
    BOOLEAN want2ndCrcCheck = TRUE;
#endif
    
    (void)dma_status;

	if (0 == pktBuffer[ETHERNET_II_TYPE_OFFSET])
        return ethFilterActionDiscard;				// packet was discurded by interrupt filter

    rxBypassData->recvFn = NULL;
    
#if (BSP_WANT_2ND_ETHERNET_CHECKSUM && ((PROCESSOR == ns7520) || (PROCESSOR == net50)))
	if (customFilterFn && customRecvFn == NULL)
    {
        /* If there is a filter but no receive function, apply CRC here,
           because an application might be receiving in the filter
        */
        if (ether_crc32(pktBuffer, pktlen))
            return ethFilterActionDiscard;  /* CRC error */
        else
            want2ndCrcCheck = FALSE;   /* already checked */
    }
#endif

    if (customFilterFn)
    {
        result = customFilterFn(pktBuffer, pktlen);
        if (result == ethFilterActionCustomReceive)
        {
            if (customRecvFn)
                rxBypassData->recvFn = customRecvFn;
            else 
                return ethFilterActionDiscard;
        }
    }
    if (result == ethFilterActionDiscard)
        return ethFilterActionDiscard;

    /* Apply packet types */
#if BSP_ENABLE_ETHERNET_PACKET_TYPES == TRUE

    if (result == ethFilterActionForward)
    {
        unsigned idx;

        for (idx = 0; idx < packetTypeCount; idx++)
        {
            if (matchesPacketType(&packetType[idx], (BYTE *)pktBuffer))
            {
                if (packetType[idx].filterCount && matchesFilter(&packetType[idx], (BYTE *)pktBuffer, dma_status, pktlen))
                    return ethFilterActionDiscard;
 
            #if (BSP_WANT_2ND_ETHERNET_CHECKSUM && ((PROCESSOR == ns7520) || (PROCESSOR == net50)))
                want2ndCrcCheck = packetType[idx].want2ndCrcCheck;
            #endif
                rxBypassData->recvFn = packetType[idx].recvFn;
                break;
            }
        }
        if (idx > packetTypeCount)
        {
            if (unclaimedPacketFn)
               rxBypassData->recvFn = unclaimedPacketFn;
            else
               return ethFilterActionDiscard;
        }
    }
#endif
    /* Calculate CRC if needed, and if has not done it already for a custom filter */
#if (BSP_WANT_2ND_ETHERNET_CHECKSUM && ((PROCESSOR == ns7520) || (PROCESSOR == net50)))
    if (want2ndCrcCheck && ether_crc32((BYTE *) pktBuffer, pktlen))
    {
       return ethFilterActionDiscard;
    }
#endif

#if BSP_USE_ETHERNET_RECV_QUEUE
    result = ethFilterActionCustomReceive;
#else
    if (rxBypassData->recvFn)
        result = ethFilterActionCustomReceive;
    else
        result = ethFilterActionForward;
#endif

    if (result == ethFilterActionCustomReceive)
    {
        rxBypassData->buffer = pktBuffer;
        rxBypassData->size   = pktlen;
    }
    return result;
}

void naEthBypassReceive(ttUserInterface interfaceHandle)
{
#if	BSP_ETH_WIFI_BRIDGE
    ethData *eth_datap = bfDeviceGetPointer(interfaceHandle);
#else
    ethData *eth_datap = tfDeviceGetPointer(interfaceHandle);
#endif

    if (eth_datap->rx_bypass)
    {
        tfStoreBypassPacketDataPtr((ttPacketPtr) eth_datap->rx_bypass, 
                              rxBypassData->buffer, rxBypassData->size);
        if (rxBypassData->recvFn)
        {
            if (!rxBypassData->recvFn((naNetMsgPtr) eth_datap->rx_bypass))
            {
                tfFreeDriverBuffer(eth_datap->rx_bypass); 
            }
        }
#if BSP_USE_ETHERNET_RECV_QUEUE
        else
        {
            tfBypassQueueAdd(&rxBypassData->eth_recvq, (ttPacketPtr) eth_datap->rx_bypass);
            tx_event_flags_set(&rxBypassData->events, 1, TX_OR);
        }
#endif
    }
}

/*ad*
 * Registers a custom raw filter and receive function for received Ethernet packets.
 * filterFn is the next filter applied to a packet after the interrupt filter, registered 
 * by @link naEthRegisterInterruptFilterFn.
 *
 * If filterFn returns ethFilterActionCustomReceive, the packet is passed to the recvFn.
 * If filterFn returns ethFilterActionDiscard, the packet is dropped by the Ethernet Driver.
 * If filterFn returns ethFilterActionForward, the packet is forwarded to the TCP/IP stack or
 * to the packet type receive routine.                       
 *
 * Packet type support @link BSP_ENABLE_ETHERNET_PACKET_TYPES is not needed for this filter.
 * If @link BSP_USE_ETHERNET_RECV_QUEUE is set to FALSE in bsp_net.h, all received Ethernet 
 * packets are processed in the Ethernet receive thread. If @link BSP_USE_ETHERNET_RECV_QUEUE 
 * is set to FALSE in bsp_net.h, only received bypass packets are processed in the 
 * thernet receive thread; all TCP/IP packets are queued and passed up to the stack in 
 * a separate thread of @link BSP_ETHERNET_RECV_QUEUE_THREAD_PRIORITY priority.
 *
 * Call this function with NULL pointers for both filterFn and recvFn to unregister a 
 * filter/receive function pair. 
 *
 * In order to receive multicast packets in bypass mode, an application must call 
 * @link eth_add_multicast for each desired multicast MAC address. The @link eth_add_multicast
 * function adds the multicast MAC address to the Ethernet multicast hash table. The Ethernet
 * driver by default configures Ethernet Station Address Filter register to accept multicast packets, 
 * using the hash table. Alternatevely Ethernet Station Address Filter can be reconfigured to 
 * accept all multicast packets.
 *
 * @note    It is recommended to register a custom filter with a non-zero receive function,
 *          in the case when the software CRC calculation is necessary. Otherwise the
 *          CRC is calculated on every received packet.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver:EthernetBypass
 * @since 6.3
 *
 * @param filterFn    Pointer to a custom filter function, must not be NULL, if recvFn != NULL.
 * @param recvFn      Pointer to a custom receive function.
 *
 * @return ETH_SUCCESS  Custom filter and receive functions have been registered
 * @return ETH_FAILURE  Invalid arguments.
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:EthernetBypass:ethCustomFilterFnType
 * @see @link BSP:Device_Drivers:EthernetDriver:EthernetBypass:ethFilterActionType
 * @see @link BSP:BSP_Configuration:EthernetDriver:EthernetBypass:BSP_USE_ETHERNET_RECV_QUEUE
*ad*/
int NAEthRegisterCustomPacketFn(ethCustomFilterFnType const filterFn, ethReceiveFnType const recvFn)
{
    int result = ETH_SUCCESS;
        
    if (filterFn == NULL && recvFn != NULL)
		result = ETH_FAILURE;
    else
    {
        ttUserInterface interfaceHandle = NULL;
        unsigned int multihome = 0;

        naIfConfigGetInterfaceHandle("eth0", &interfaceHandle, &multihome);
        tfBypassLockDevice(interfaceHandle);

        customFilterFn  = filterFn;
        customRecvFn    = recvFn;

        tfBypassUnlockDevice(interfaceHandle);
    }
    return result;
}

#if BSP_ENABLE_ETHERNET_INTERRUPT_FILTER

/*ad*
 * Registers a custom raw filter function to be called in the interrupt context for received Ethernet packets.
 * intFilterFn is the first filter applied to a packet. This filter can be used to reply to packets for which 
 * the smallest RTT variation is critical. To achieve the smallest RTT variation for a certain type of packets,
 * an application would need to reply to these packets directly in the interrupt filter, using 
 * @link naEthBypassTransmit.
 *
 * If filterFn returns ethFilterActionDiscard, the packet is dropped by the Ethernet Driver, 
 * otherwise the packet is forwarded to the Ethernet receive thread. 
 *
 * Unlike the custom filter, called from the receive thread, the interrupt filter can not forward a packet
 * to the custom receive function. This is because at the time of receive ISR the packet only has a data 
 * buffer, but does not have a message handle of a @link naNetMsgPtr type, associated with the packet.
 *
 * Because an interrupt filter function is called in the  context of the interrupt, it must not use any blocking 
 * function calls. It can't call malloc, ThreadX functions to get a semaphore, mutex, event flag, or other blocking 
 * functions. The Ethernet API functions that are non-blocking and can be called from the interrupt filter are:
 * @link naEthBypassTransmit, @link naNetMsgGetDataBufferPtr, @link naNetMsgGetDataPtr, @link naNetMsgStoreDataPtr 
 * 
 * Even though @link naEthBypassTransmit can be called in the interrupt filter, the received packet can't be reused for 
 * this transmit. If an application is echoing received packets, packet data would have to be copied from a received 
 * a transmit packet.
 * 
 * The interrupt filter should return ethFilterActionDiscard in two cases: if it has recognized that  
 * the application wants to filter this packet out, or if the interrupt filter has consumed a packet,
 * and the packet would not be needed after return of the interrupt filter. In all other cases the interrupt
 * filter must return ethFilterActionForward.
 *
 * An interrupt filter and custom receive filter are independent from each other and an application can call both 
 * naEthRegisterInterruptFilterFn and @link NAEthRegisterCustomPacketFn. The same packet can be passed to both 
 * filters, if the interrupt filter returns ethFilterActionForward.
 *
 * In order to receive multicast packets in bypass mode, an application must call 
 * @link eth_add_multicast for each desired multicast MAC address. The @link eth_add_multicast
 * function adds the multicast MAC address to the Ethernet multicast hash table. The Ethernet
 * driver by default configures Ethernet Station Address Filter register to accept multicast packets, 
 * using the hash table. Alternatevely Ethernet Station Address Filter can be reconfigured to 
 * accept all multicast packets.
 *
 *  
 * The @link BSP_ENABLE_ETHERNET_INTERRUPT_FILTER must be set to TRUE in bsp_net.h to enable the
 * interrupt filter support.
 *
 * @note    See udpechod sample application for the example of using an Ethernet interrupt filter.
 *
 * @external
 * @include "eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver:EthernetBypass
 * @since	 7.5
 *
 * @param intFilterFn    Pointer to an interrupt filter function
 *
 * @return ETH_SUCCESS  Interrupt filter function have been registered
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:EthernetBypass:ethCustomFilterFnType
 * @see @link BSP:Device_Drivers:EthernetDriver:EthernetBypass:ethFilterActionType
*ad*/
int naEthRegisterInterruptFilterFn(ethCustomFilterFnType const intFilterFn)
{
    isrFilterFn   = intFilterFn;

    return ETH_SUCCESS;

}

void naEthIsrFilter(fb_buffer_desc_t *desc)
{
	if (isrFilterFn && desc)
	{
		char *buffer = (char *)ReadRegMask(DMA_SBP(desc), DMA_SBP_MASK);
		unsigned size = ReadRegMask(DMA_BUFLEN(desc), DMA_BUFLEN_MASK);
                
		NAAfterDMA(NA_DEVICE_TO_MEMORY_DMA, NULL, buffer, size);	// this does nothing

		// Call a user filter function which will decide to discard a packet 
		// (unwanted, or consume and discard it) or pass it up. 
		if (isrFilterFn(buffer, size) == ethFilterActionDiscard)	// This user function decides to keep or discard a packet
			buffer[ETHERNET_II_TYPE_OFFSET] = 0;					// Mark a packet to discard it in receive thread
	}
}
#endif

#if BSP_ENABLE_ETHERNET_BYPASS

/*ad*
 * Transmits an Ethernet bypass packet
 *
 * Unlike @link naEthTransmit, naEthBypassTransmit uses a queue, separate from the TCP/IP stack, 
 * to send packets. To enable bypass transmit support @link BSP_ENABLE_ETHERNET_BYPASS 
 * must be set to TRUE in bsp_net.h. 
 *
 * The total number of transmit DMA buffer descriptors is split to be used for Ethernet 
 * bypass and the TCP/IP stack. @link BSP_ETHERNET_BYPASS_SEND_BUFFERS specifies the number of 
 * bypass DMA buffer descriptors. The rest are used by the TCP/IP stack. 
 *
 * This function can be called to reuse transmitted packet structures. It also can be 
 * used to transmit out of the external data buffer.
 *
 * Use a non-zero txCompleteFn function to preserve a packet structure after the 
 * transmission. The driver invokes this callback to let an application know that the 
 * the transmission has completed and the packet memory can be reused. The ethernet driver 
 * frees the packet if naEthBypassTransmit was called with txCompleteFn == NULL.
 *
 * If the packet is transmitted from an external data buffer, the non-zero txCompleteFn 
 * callback must be used, because the driver does not free the data buffer when it frees 
 * a packet. 
 *
 * The packet data must include a valid Ethernet header with the correct 
 * destination and source addresses. Use @link naNetMsgGetDataPtr, @link naNetMsgGetDataBufferPtr, 
 * and @link naNetMsgStoreDataPtr functions to gain access to the message data and size, 
 * data buffer and data buffer size, or store new data pointer and size.
 * 
 * An application might be reusing a transmit packet structure for the application's
 * lifetime, but if it does not need the packet any longer, it should free it by calling 
 * @link naNetMsgFree.
 *
 * @external
 * @include 	"eth_api.h"
 * @category BSP:Device_Drivers:EthernetDriver:EthernetBypass 
 * @since 7.0
 *
 * @note    This function replaces NAEthBypassTransmit. 
 *
 * @param msg_handle    Network message handle.
 * @param txCompleteFn  Pointer to a callback to notify an application that
 *                      the transmission is complete. Can be NULL. Non-zero
 *                      function pointer is needed to preserve the packet structure
 *                      after the transmission.
 *
 * @return ETH_SUCCESS   The packet has been added to the device transmit queue.
 * @return ETH_FAILURE   Invalid arguments. 
 *
 * @see @link BSP:Device_Drivers:EthernetDriver:EthernetBypass:ethNotifyTxCompleteFnType
 *
*ad*/
int naEthBypassTransmit(naNetMsgPtr msg_handle, ethNotifyTxCompleteFnType txCompleteFn)
{
    ttUserInterface interfaceHandle = NULL;
    ttPacketPtr packet = (ttPacketPtr)msg_handle;
    int result = ETH_FAILURE;
    unsigned int multihome = 0;
    TX_INTERRUPT_SAVE_AREA;
    (void) txCompleteFn;

    if (msg_handle && naIfConfigGetInterfaceHandle("eth0", &interfaceHandle, &multihome) == NASTATUS_SUCCESS)
    {
        ttUserPacketPtr upacket = &packet->pktUserStruct;
		fb_buffer_desc_t *desc;

#if	BSP_ETH_WIFI_BRIDGE
	    ethData *eth_datap = bfDeviceGetPointer(interfaceHandle);
#else
		ethData *eth_datap = tfDeviceGetPointer(interfaceHandle);
#endif

        if (upacket->pktuLinkDataPtr == NULL || 
            upacket->pktuLinkDataLength < MIN_9750_PACKET_SIZE || 
            upacket->pktuLinkDataLength > ETH_MAX_PACKET_LENGTH)
            return result;

        tfSetBypassPacketDevicePtr(packet, (struct tsDeviceEntry *) interfaceHandle);
        tfSetBypassPacketUserCallback(packet, (ttUserFreeFuncPtr) txCompleteFn);

        TX_DISABLE;
        if (txBypassData->submitted_cnt >= BSP_ETHERNET_BYPASS_SEND_BUFFERS)
        {
            /* It's still full.  Return a failure and try again later. */
            TX_RESTORE;
            ++eth_datap->eth_stats.tx_full;
            goto ret;
        }
        else
        {
            txBypassData->submitted_cnt++;
			desc = eth_datap->tx_in;
			eth_datap->tx_in = ethNextTxDescr(eth_datap->tx_in);
            TX_RESTORE;
        }

        tfBypassQueueAdd(&txBypassData->eth_sendq, packet);

#if NA_ETH_SET_PACKET_TRAILER_SIZE 
		/* 
		 * If user packet trailer option is enabled (NA_ETH_SET_PACKET_TRAILER_SIZE != 0),
		 * the packet size needs to be increased to the minimum + the trailer size,
		 * and manually padded, if it is smaller than minimum. The buffer has been allocated 
		 * with the padding and trailer size added.
		 */
		if (naEthPacketTrailerSize)
		{
			unsigned int padding_size = 0;

			if (upacket->pktuLinkDataLength < ETH_MIN_PACKET_LENGTH)
			{
				padding_size = ETH_MIN_PACKET_LENGTH - upacket->pktuLinkDataLength;
				memset(upacket->pktuLinkDataPtr + size, 0, padding_size);

			}
			/* Add your code here to add the trailer at (upacket->pktuLinkDataPtr + size + padding_size) */

			/* Increase the buffer size */
			size += padding_size + naEthPacketTrailerSize;
		}
#endif
        naEthTransmitPacketBuffer(eth_datap, desc, desc, upacket->pktuLinkDataPtr, 
                                  upacket->pktuLinkDataLength, 
                                  ETH_TX_LAST_FLAG | ETH_TX_BYPASS_FLAG);
        result = ETH_SUCCESS;
    }
ret:
    return result;
}


void naEthNotifyTxBypass(unsigned completed_cnt)
{
    txBypassData->completed_cnt += completed_cnt;
    txBypassData->submitted_cnt -= completed_cnt;
    
    if (txBypassData->completed_cnt > 10)
    {
        tx_event_flags_set(&txBypassData->events, 1, TX_OR);
    }
}

static void ethBypassSendCompleteTask(ULONG input)
{ 
    unsigned long flags = 0;
    unsigned idx, completed_cnt;
    ttPacketPtr packet;
    TX_INTERRUPT_SAVE_AREA;
    (void)input;

    while (1)
    {
        tx_event_flags_get(&txBypassData->events, 1, TX_OR_CLEAR, &flags, 20); 

        TX_DISABLE;
        completed_cnt = txBypassData->completed_cnt;
        txBypassData->completed_cnt = 0;
        TX_RESTORE;

        for (idx = 0; idx < completed_cnt; idx++)
        {
            packet = tfBypassQueueRemove(&txBypassData->eth_sendq);
            if (packet)
            {
               ethNotifyTxCompleteFnType txCompleteFn = (ethNotifyTxCompleteFnType) tfGetBypassPacketUserCallback(packet);
               tfSetBypassPacketUserCallback(packet, NULL);

               if (txCompleteFn)
                   txCompleteFn((naNetMsgPtr) packet);
               else
                   tfFreeDriverBuffer(&packet->pktUserStruct);
            }
        }
    }
}
#endif

#if BSP_USE_ETHERNET_RECV_QUEUE
static void ethReceiveQueueTask(ULONG input)
{
    ttUserInterface interfaceHandle;
    unsigned long flags = 0;
    unsigned multihome = 0;
    (void)input;

    while (1)
    {
        tx_event_flags_get(&rxBypassData->events, 1, TX_OR_CLEAR, &flags, TX_WAIT_FOREVER);

        if (naIfConfigGetInterfaceHandle("eth0", &interfaceHandle, &multihome) == NASTATUS_SUCCESS)
        {
            while (rxBypassData->eth_recvq.head) 
            {
#if BSP_ETH_WIFI_BRIDGE
                bfRecvInterface(interfaceHandle); 
#else
                tfRecvInterface(interfaceHandle); 
#endif
            }
        }
    }
}

int naEthReceive(ttUserInterface interfaceHandle,
	char TM_FAR * TM_FAR * dataPtr,
	int  TM_FAR *          dataLength,
	ttUserBufferPtr        bufHandlePtr
	)
{
    ttPacketPtr ppacket;
    char *buffer_ptr;
    unsigned length;
    (void) interfaceHandle;

    ppacket = tfBypassQueueRemove(&rxBypassData->eth_recvq);
    if (ppacket && 
        tfGetBypassPacketDataPtr(ppacket, &buffer_ptr, &length) == ETH_SUCCESS)
    {
        *bufHandlePtr   = &ppacket->pktUserStruct;
        *dataPtr        = buffer_ptr;
        *dataLength     = (int)length;
        return TM_DEV_OKAY;
    }
    return TM_DEV_ERROR;
}
#endif

int naEthBypassInit(void)
{
#if BSP_USE_ETHERNET_RECV_QUEUE || BSP_ENABLE_ETHERNET_BYPASS
    int errorCode;
    char *pstack;
#endif
    rxBypassData = malloc(sizeof (rxBypassDataType));
    if (rxBypassData == NULL)
     {
        printf("naEthBypassInit: malloc failed!\n");
        return TM_DEV_ERROR;
    }
    memset(rxBypassData, 0, sizeof (rxBypassDataType));

#if BSP_USE_ETHERNET_RECV_QUEUE
    pstack = malloc(THREAD_STACK_SIZE);

    if (pstack == NULL)
    {
        printf("naEthBypassInit: malloc failed!\n");
        return TM_DEV_ERROR;
    }
    errorCode = tx_event_flags_create(&rxBypassData->events, "Bypass Rx Events");
    if (errorCode != TX_SUCCESS)
    {
	    printf("naEthBypassInit: tx_event_flags_create failed for bypass task! %d\n", errorCode);
        return TM_DEV_ERROR;
    }
    
    errorCode = tx_thread_create(&rxBypassData->tcb,
                              "Treck Receive", 
                              ethReceiveQueueTask, 
                              0,
                              pstack,
                              THREAD_STACK_SIZE, 
                              BSP_ETHERNET_RECV_QUEUE_THREAD_PRIORITY, 
                              BSP_ETHERNET_RECV_QUEUE_THREAD_PRIORITY,
                              TX_NO_TIME_SLICE, 
                              TX_AUTO_START);

    if (errorCode != TX_SUCCESS)
    {
	    printf("naEthBypassInit: tx_thread_create failed for bypass task! %d\n", errorCode);
        return TM_DEV_ERROR;
    }
#endif

#if BSP_ENABLE_ETHERNET_BYPASS
  
    txBypassData = malloc(sizeof (txBypassDataType));
    pstack = malloc(THREAD_STACK_SIZE);

    if (txBypassData == NULL || pstack == NULL)
    {
        printf("naEthBypassInit: malloc failed!\n");
        return TM_DEV_ERROR;
    }
    memset(txBypassData, 0, sizeof (txBypassDataType));

    errorCode = tx_event_flags_create(&txBypassData->events, "Bypass Events");
    if (errorCode != TX_SUCCESS)
    {
	    printf("naEthBypassInit: tx_event_flags_create failed for bypass task! %d\n", errorCode);
        return TM_DEV_ERROR;
    }
    
    errorCode = tx_thread_create(&txBypassData->tcb,
                              "Bypass Send Comlete", 
                              ethBypassSendCompleteTask, 
                              0,
                              pstack,
                              THREAD_STACK_SIZE, 
                              BYPASS_SEND_COMLPETE_TASK_PRI, 
                              BYPASS_SEND_COMLPETE_TASK_PRI,
                              TX_NO_TIME_SLICE, 
                              TX_AUTO_START);

    if (errorCode != TX_SUCCESS)
    {
	    printf("naEthBypassInit: tx_thread_create failed for bypass task! %d\n", errorCode);
        return TM_DEV_ERROR;
    }
#endif
    return TM_DEV_OKAY;
}
#else
int naEthBypassInit(void)
{
    return  TM_DEV_OKAY;
}
#endif

#if NA_ETH_SET_PACKET_TRAILER_SIZE

unsigned int naEthPacketTrailerSize = NA_ETH_SET_PACKET_TRAILER_SIZE;

void naEthSetPacketTrailer(unsigned int trailerSize)
{
	naEthPacketTrailerSize = trailerSize;
	(void) tfInitTreckOptions(TM_OPTION_SEND_TRAILER_SIZE, trailerSize);
}

#endif



#ifdef NA_ARP_PING_ENABLED
/*
 *
 *  Function: int naArpPingEnable(int active)
 *
 *  Description: This function will be available and used to enable or disable
 *  the ARP Ping capability.  When the NA_ARP_PING_ENABLED define is true, a
 *  call to this function with the active argument non-zero sets the protocol
 *  to active.  (A call to the function with active set to zero, deactivates
 *  the protocol.)
 *
 *  Parameters:
 *
 *      int active
 *
 *  Return Values:
 *
 *      The function returns 0.
 *
 */
int naArpPingEnable(int active)
{
    ttUserInterface interfaceHandle = NULL;
    unsigned int multihome = 0;
    ttDeviceEntryPtr devPtr; 

    naIfConfigGetInterfaceHandle("eth0", &interfaceHandle, &multihome);

    devPtr = (ttDeviceEntryPtr)interfaceHandle;

    if (active)
    {
	    devPtr->drvPingArpFuncPtr = (ttDevPingArpFuncPtr)tfIcmpPingArpCallback;
    }
    else
    {
	    devPtr->drvPingArpFuncPtr = (ttDevPingArpFuncPtr)0;
    }

    return NASTATUS_SUCCESS;
}
#endif



