?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*********************************************************************
 *
 *      User Datagram Protocol (UDP) Communications Layer
 *  Module for Microchip TCP/IP Stack
 *       -Provides unreliable, minimum latency transport of application 
 *    datagram (packet) oriented data
 *       -Reference: RFC 768
 *
 *********************************************************************
 * FileName:        UDP.c
 * Dependencies:    IP, Ethernet (ENC28J60.c or ETH97J60.c)
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *                                      Microchip C30 v3.12 or higher
 *                                      Microchip C18 v3.30 or higher
 *                                      HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *              ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *              used in conjunction with a Microchip ethernet controller for
 *              the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date    Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     3/19/01  Original        (Rev 1.0)
 * Nilesh Rajbharti     2/26/03  Fixed UDPGet and UDPProcess bugs
 *                               as discovered and fixed by John Owen
 *                               of Powerwave.
 *                               1. UDPGet would return FALSE on last good byte
 *                               2. UDPProcess was incorrectly calculating length.
 * Nilesh Rajbharti     5/19/03  Added bFirstRead flag similar to TCP
 *                               to detect very first UDPGet and
 *                               reset MAC Rx pointer to begining of
 *                               UDP data area.  This would ensure that
 *                               if UDP socket has pending Rx data and
 *                               another module resets MAC Rx pointer,
 *                               next UDP socket Get would get correct
 *                               data.
 * Robert Sloan (RSS)    5/29/03 Improved FindMatchingSocket()
 * Nilesh Rajbharti     12/2/03  Added UDPChecksum logic in UDPProcess()
 * Nilesh Rajbharti     12/5/03  Modified UDPProcess() and FindMatchingSocket()
 *                               to include localIP as new parameter.
 *                               This corrects pseudo header checksum
 *                               logic in UDPProcess().
 *                               It also corrects broadcast packet
 *                               matching correct in FindMatchingSocket().
 * Howard Schlunder             1/16/06  Fixed an imporbable RX checksum bug 
 *                                                               when using a Microchip Ethernet controller)
 * Howard Schlunder             6/02/06  Fixed a bug where all RXed UDP packets 
 *                                                               without a checksum (0x0000) were thrown
 *                                                               away.  No checksum is legal in UDP.
 * Howard Schlunder             8/10/06  Fixed a bug where UDP sockets would 
 *                                                               unintentionally keep the remote MAC 
 *                                                               address cached, even after calling 
 *                                                               UDPInit(), UDPClose(), or reseting 
 *                                                               the part without clearing all the 
 *                                                               PIC memory.
 ********************************************************************/
#define __UDP_C

#include "TCPIP Stack/TCPIP.h"

#if defined(STACK_USE_UDP)

/****************************************************************************
  Section:
        Configuration Parameters
  ***************************************************************************/

// First port number for randomized local port number selection
#define LOCAL_UDP_PORT_START_NUMBER (4096u)

// Last port number for randomized local port number selection
#define LOCAL_UDP_PORT_END_NUMBER   (8192u)

/****************************************************************************
  Section:
        UDP Global Variables
  ***************************************************************************/

// Stores an array of information pertaining to each UDP socket
UDP_SOCKET_INFO         UDPSocketInfo[MAX_UDP_SOCKETS];

// Indicates which UDP socket is currently active
UDP_SOCKET                      activeUDPSocket;

WORD UDPTxCount;        // Number of bytes written to this UDP segment
WORD UDPRxCount;        // Number of bytes read from this UDP segment
static UDP_SOCKET       LastPutSocket = INVALID_UDP_SOCKET;     // Indicates the last socket to which data was written
static WORD wPutOffset;         // Offset from beginning of payload where data is to be written.
static WORD wGetOffset;         // Offset from beginning of payload from where data is to be read.

// Stores various flags for the UDP module
static struct
{
        unsigned char bFirstRead : 1;           // No data has been read from this segment yet
        unsigned char bWasDiscarded : 1;        // The data in this segment has been discarded
} Flags;

// Indicates which socket has currently received data for this loop
static UDP_SOCKET SocketWithRxData = INVALID_UDP_SOCKET;

/****************************************************************************
  Section:
        Function Prototypes
  ***************************************************************************/

static UDP_SOCKET FindMatchingSocket(UDP_HEADER *h, NODE_INFO *remoteNode,
                                    IP_ADDR *localIP);

/****************************************************************************
  Section:
        Connection Management Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        void UDPInit(void)

  Summary:
        Initializes the UDP module.

  Description:
        Initializes the UDP module.  This function initializes all the UDP 
        sockets to the closed state.

  Precondition:
        None

  Parameters:
        None

  Returns:
        None
        
  Remarks:
        This function is called only one during lifetime of the application.
  ***************************************************************************/
void UDPInit(void)
{
    UDP_SOCKET s;

    for ( s = 0; s < MAX_UDP_SOCKETS; s++ )
    {
                UDPClose(s);
    }
        Flags.bWasDiscarded = 1;
}


/*****************************************************************************
  Function:
        void UDPTask(void)

  Summary:
        Performs state management and housekeeping for UDP.
        
  Description:
        Performs state management and housekeeping for UDP.  This is an internal
        function meant to be called by StackTask() (not a user API).

  Precondition:
        None

  Parameters:
        None

  Return Values:
        None
        
  Remarks:
        UDPTask() is called once per StackTask() iteration to ensure that calls 
        to UDPIsPutReady() always update the Ethernet Write pointer location 
        between StackTask() iterations.
  ***************************************************************************/
void UDPTask(void)
{
        LastPutSocket = INVALID_UDP_SOCKET;
}


/*****************************************************************************
  Function:
        UDP_SOCKET UDPOpen(UDP_PORT localPort, NODE_INFO* remoteNode, 
                                                UDP_PORT remotePort)

  Summary:
        Creates a UDP socket handle for transmiting or receiving UDP packets.
        
  Description:
        Creates a UDP socket handle for transmiting or receiving UDP packets.  
        Call this function to obtain a handle required by other UDP function.

  Precondition:
        UDPInit() must have been previously called.

  Parameters:
        localPort - UDP port number to listen on.  If 0, stack will dynamically 
                assign a unique port number to use.
        remoteNode - Pointer to remote node info (MAC and IP address) for this
                connection.  If this is a server socket (receives the first packet) 
                or the destination is the broadcast address, then this parameter
                should be NULL.
        remotePort - For client sockets, the remote port number.

  Return Values:
        Success -
                A UDP socket handle that can be used for subsequent UDP API calls.
        Failure -
                INVALID_UDP_SOCKET.  This function fails when no more UDP socket 
                handles are available.  Increase MAX_UDP_SOCKETS to make more sockets 
                available.
        
  Remarks:
        When finished using the UDP socket handle, call the UDPClose() function 
        to free the socket and delete the handle.
  ***************************************************************************/
UDP_SOCKET UDPOpen(UDP_PORT localPort,
                   NODE_INFO *remoteNode,
                   UDP_PORT remotePort)
{
    UDP_SOCKET s;
    UDP_SOCKET_INFO *p;

        // Local temp port numbers.
        static WORD NextPort __attribute__((persistent));


    p = UDPSocketInfo;
    for ( s = 0; s < MAX_UDP_SOCKETS; s++ )
    {
        if(p->localPort == INVALID_UDP_PORT)
        {
                        p->localPort = localPort;       

                        if(localPort == 0x0000u)
                        {
                                if(NextPort > LOCAL_UDP_PORT_END_NUMBER || NextPort < LOCAL_UDP_PORT_START_NUMBER)
                                        NextPort = LOCAL_UDP_PORT_START_NUMBER;
        
                    p->localPort    = NextPort++;
                        }

            // If remoteNode is supplied, remember it.
            if(remoteNode)
            {
                memcpy((void*)&p->remoteNode,
                        (const void*)remoteNode,
                        sizeof(p->remoteNode));
            }
            else
                        {
                                // else Set broadcast address
                                memset((void*)&p->remoteNode, 0xFF, sizeof(p->remoteNode));
                        }

            p->remotePort   = remotePort;

            // Mark this socket as active.
            // Once an active socket is set, subsequent operation can be
            // done without explicitely supply socket identifier.
            activeUDPSocket = s;
            return s;
        }
        p++;
    }

    return (UDP_SOCKET)INVALID_UDP_SOCKET;
}




/*****************************************************************************
  Function:
        void UDPClose(UDP_SOCKET s)

  Summary:
        Closes a UDP socket and frees the handle.
        
  Description:
        Closes a UDP socket and frees the handle.  Call this function to release
        a socket and return it to the pool for use by future communications.

  Precondition:
        UDPInit() must have been previously called.

  Parameters:
        s - The socket handle to be released.  If an illegal handle value is 
                provided, the function safely does nothing.

  Returns:
        None
        
  Remarks:
        This function does not affect the previously designated active socket.
  ***************************************************************************/
void UDPClose(UDP_SOCKET s)
{
        if(s >= MAX_UDP_SOCKETS)
                return;

        UDPSocketInfo[s].localPort = INVALID_UDP_PORT;
        UDPSocketInfo[s].remoteNode.IPAddr.Val = 0x00000000;
}


/*****************************************************************************
  Function:
        void UDPSetTxBuffer(WORD wOffset)

  Summary:
        Moves the pointer within the TX buffer.
        
  Description:
        This function allows the write location within the TX buffer to be 
        specified.  Future calls to UDPPut, UDPPutArray, UDPPutString, etc will
        write data from the indicated location.

  Precondition:
        UDPInit() must have been previously called and a socket is currently 
        active.

  Parameters:
        wOffset - Offset from beginning of UDP packet data payload to place the
                write pointer.

  Returns:
        None
  ***************************************************************************/
void UDPSetTxBuffer(WORD wOffset)
{
        IPSetTxBuffer(wOffset+sizeof(UDP_HEADER));
        wPutOffset = wOffset;
}


/*****************************************************************************
  Function:
        void UDPSetRxBuffer(WORD wOffset)

  Summary:
        Moves the pointer within the RX buffer.
        
  Description:
        This function allows the read location within the RX buffer to be 
        specified.  Future calls to UDPGet and UDPGetArray will read data from
        the indicated location forward.

  Precondition:
        UDPInit() must have been previously called and a socket is currently 
        active.

  Parameters:
        wOffset - Offset from beginning of UDP packet data payload to place the
                read pointer.

  Returns:
        None
  ***************************************************************************/
void UDPSetRxBuffer(WORD wOffset)
{
        IPSetRxBuffer(wOffset+sizeof(UDP_HEADER));
        wGetOffset = wOffset;
}



/****************************************************************************
  Section:
        Transmit Functions
  ***************************************************************************/
  
/*****************************************************************************
  Function:
        WORD UDPIsPutReady(UDP_SOCKET s)

  Summary:
        Determines how many bytes can be written to the UDP socket.
        
  Description:
        This function determines if bytes can be written to the specified UDP
        socket.  It also prepares the UDP module for writing by setting the 
        indicated socket as the currently active connection.

  Precondition:
        UDPInit() must have been previously called.

  Parameters:
        s - The socket to be made active

  Returns:
        The number of bytes that can be written to this socket.
  ***************************************************************************/
WORD UDPIsPutReady(UDP_SOCKET s)
{
        if(!MACIsTxReady())
                return 0;

        if(LastPutSocket != s)
        {
                LastPutSocket = s;
                UDPTxCount = 0;
                UDPSetTxBuffer(0);
        }

        activeUDPSocket = s;

        return MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER) - UDPTxCount;
}

/*****************************************************************************
  Function:
        BOOL UDPPut(BYTE v)

  Summary:
        Writes a byte to the currently active socket.
        
  Description:
        This function writes a single byte to the currently active UDP socket, 
        while incrementing the buffer length.  UDPIsPutReady should be used 
        before calling this function to specify the currently active socket.

  Precondition:
        UDPIsPutReady() was previously called to specify the current socket.

  Parameters:
        v - The byte to be loaded into the transmit buffer.

  Return Values:
        TRUE - The byte was successfully written to the socket.
        FALSE - The transmit buffer is already full and so the write failed.
  ***************************************************************************/
BOOL UDPPut(BYTE v)
{
        // See if we are out of transmit space.
        if(wPutOffset >= (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER)))
        {
                return FALSE;
        }

    // Load application data byte
    MACPut(v);
        wPutOffset++;
        if(wPutOffset > UDPTxCount)
                UDPTxCount = wPutOffset;

    return TRUE;
}

/*****************************************************************************
  Function:
        WORD UDPPutArray(BYTE *cData, WORD wDataLen)

  Summary:
        Writes an array of bytes to the currently active socket.
        
  Description:
        This function writes an array of bytes to the currently active UDP socket, 
        while incrementing the buffer length.  UDPIsPutReady should be used 
        before calling this function to specify the currently active socket.

  Precondition:
        UDPIsPutReady() was previously called to specify the current socket.

  Parameters:
        cData - The array to write to the socket.
        wDateLen - Number of bytes from cData to be written.
        
  Returns:
        The number of bytes successfully placed in the UDP transmit buffer.  If
        this value is less than wDataLen, then the buffer became full and the
        input was truncated.
  ***************************************************************************/
WORD UDPPutArray(BYTE *cData, WORD wDataLen)
{
        WORD wTemp;

        wTemp = (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER)) - wPutOffset;
        if(wTemp < wDataLen)
                wDataLen = wTemp;

        wPutOffset += wDataLen;
        if(wPutOffset > UDPTxCount)
                UDPTxCount = wPutOffset;

    // Load application data bytes
    MACPutArray(cData, wDataLen);

    return wDataLen;
}

/*****************************************************************************
  Function:
        WORD UDPPutROMArray(ROM BYTE *cData, WORD wDataLen)

  Summary:
        Writes an array of bytes from ROM to the currently active socket.
        
  Description:
        This function writes an array of bytes from ROM to the currently active 
        UDP socket, while incrementing the buffer length.  UDPIsPutReady should 
        be used before calling this function to specify the currently active 
        socket.

  Precondition:
        UDPIsPutReady() was previously called to specify the current socket.

  Parameters:
        cData - The array to write to the socket.
        wDateLen - Number of bytes from cData to be written.
        
  Returns:
        The number of bytes successfully placed in the UDP transmit buffer.  If
        this value is less than wDataLen, then the buffer became full and the
        input was truncated.
        
  Remarks:
        This function is aliased to UDPPutArray on non-PIC18 platforms.
  ***************************************************************************/
#if defined(__18CXX)
WORD UDPPutROMArray(ROM BYTE *cData, WORD wDataLen)
{
        WORD wTemp;

        wTemp = (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER)) - wPutOffset;
        if(wTemp < wDataLen)
                wDataLen = wTemp;

        wPutOffset += wDataLen;
        if(wPutOffset > UDPTxCount)
                UDPTxCount = wPutOffset;

    // Load application data bytes
    MACPutROMArray(cData, wDataLen);

    return wDataLen;
}
#endif

/*****************************************************************************
  Function:
        BYTE* UDPPutString(BYTE *strData)

  Summary:
        Writes null-terminated string to the currently active socket.
        
  Description:
        This function writes a null-terminated string to the currently active 
        UDP socket, while incrementing the buffer length.  UDPIsPutReady should 
        be used before calling this function to specify the currently active
        socket.

  Precondition:
        UDPIsPutReady() was previously called to specify the current socket.

  Parameters:
        cData - Pointer to the string to be written to the socket.
        
  Returns:
        A pointer to the byte following the last byte written.  Note that this
        is different than the UDPPutArray functions.  If this pointer does not
        dereference to a NULL byte, then the buffer became full and the input
        data was truncated.
  ***************************************************************************/
BYTE* UDPPutString(BYTE *strData)
{
        return strData + UDPPutArray(strData, strlen((char*)strData));
}

/*****************************************************************************
  Function:
        BYTE* UDPPutString(BYTE *strData)

  Summary:
        Writes null-terminated string from ROM to the currently active socket.
        
  Description:
        This function writes a null-terminated string from ROM to the currently
        active UDP socket, while incrementing the buffer length.  UDPIsPutReady
        should be used before calling this function to specify the currently
        active socket.

  Precondition:
        UDPIsPutReady() was previously called to specify the current socket.

  Parameters:
        cData - Pointer to the string to be written to the socket.
        
  Returns:
        A pointer to the byte following the last byte written.  Note that this
        is different than the UDPPutArray functions.  If this pointer does not
        dereference to a NULL byte, then the buffer became full and the input
        data was truncated.
  
  Remarks:
        This function is aliased to UDPPutString on non-PIC18 platforms.
  ***************************************************************************/
#if defined(__18CXX)
ROM BYTE* UDPPutROMString(ROM BYTE *strData)
{
        return strData + UDPPutROMArray(strData, strlenpgm((ROM char*)strData));
}
#endif

/*****************************************************************************
  Function:
        void UDPFlush(void)

  Summary:
        Transmits all pending data in a UDP socket.
        
  Description:
        This function builds a UDP packet with the pending TX data and marks it 
        for transmission over the network interface.  Since UDP is a frame-based
        protocol, this function must be called before returning to the main
        stack loop whenever any data is written.

  Precondition:
        UDPIsPutReady() was previously called to specify the current socket, and
        data has been written to the socket using the UDPPut family of functions.

  Parameters:
        None
        
  Returns:
        None

  Remarks:
        Note that unlike TCPFlush, UDPFlush must be called before returning to 
        the main stack loop.  There is no auto transmit for UDP segments.
  ***************************************************************************/
void UDPFlush(void)
{
    UDP_HEADER      h;
    UDP_SOCKET_INFO *p;
    WORD                        wUDPLength;

    p = &UDPSocketInfo[activeUDPSocket];

        wUDPLength = UDPTxCount + sizeof(UDP_HEADER);

        // Generate the correct UDP header
    h.SourcePort        = swaps(p->localPort);
    h.DestinationPort   = swaps(p->remotePort);
    h.Length            = swaps(wUDPLength);
        h.Checksum                      = 0x0000;
    
        // Calculate IP pseudoheader checksum if we are going to enable 
        // the checksum field
        #if defined(UDP_USE_TX_CHECKSUM)
        {
                PSEUDO_HEADER   pseudoHeader;
                
                pseudoHeader.SourceAddress      = AppConfig.MyIPAddr;
                pseudoHeader.DestAddress    = p->remoteNode.IPAddr;
                pseudoHeader.Zero           = 0x0;
                pseudoHeader.Protocol       = IP_PROT_UDP;
                pseudoHeader.Length                     = wUDPLength;
                SwapPseudoHeader(pseudoHeader);
                h.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader));
        }
        #endif

        // Position the hardware write pointer where we will need to 
        // begin writing the IP header
        MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER));
        
        // Write IP header to packet
        IPPutHeader(&p->remoteNode, IP_PROT_UDP, wUDPLength);

    // Write UDP header to packet
    MACPutArray((BYTE*)&h, sizeof(h));
    
        // Calculate the final UDP checksum and write it in, if enabled
        #if defined(UDP_USE_TX_CHECKSUM)
        {
        PTR_BASE        wReadPtrSave;
        WORD            wChecksum;

                wReadPtrSave = MACSetReadPtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER));
                wChecksum = CalcIPBufferChecksum(wUDPLength);
                if(wChecksum == 0x0000u)
                        wChecksum = 0xFFFF;
                MACSetReadPtr(wReadPtrSave);
                MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + 6);    // 6 is the offset to the Checksum field in UDP_HEADER
                MACPutArray((BYTE*)&wChecksum, sizeof(wChecksum));
        }
        #endif
    
        // Transmit the packet
    MACFlush();

        // Reset packet size counter for the next TX operation
    UDPTxCount = 0;
        LastPutSocket = INVALID_UDP_SOCKET;
}



/****************************************************************************
  Section:
        Receive Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        WORD UDPIsGetReady(UDP_SOCKET s)

  Summary:
        Determines how many bytes can be read from the UDP socket.
        
  Description:
        This function determines if bytes can be read from the specified UDP
        socket.  It also prepares the UDP module for reading by setting the 
        indicated socket as the currently active connection.

  Precondition:
        UDPInit() must have been previously called.

  Parameters:
        s - The socket to be made active (which has already been opened or is
                listening)

  Returns:
        The number of bytes that can be read from this socket.
  ***************************************************************************/
WORD UDPIsGetReady(UDP_SOCKET s)
{
    activeUDPSocket = s;
        if(SocketWithRxData != s)
                return 0;

    // If this is the very first time we are accessing this packet, 
    // move the read point to the begining of the packet.
    if(Flags.bFirstRead)
    {
        Flags.bFirstRead = 0;
        UDPSetRxBuffer(0);
    }

    return UDPRxCount - wGetOffset;
}

/*****************************************************************************
  Function:
        BOOL UDPGet(BYTE *v)

  Summary:
        Reads a byte from the currently active socket.
        
  Description:
        This function reads a single byte from the currently active UDP socket, 
        while decrementing the remaining buffer length.  UDPIsGetReady should be 
        used before calling this function to specify the currently active socket.

  Precondition:
        UDPIsGetReady() was previously called to specify the current socket.

  Parameters:
        v - The buffer to receive the data being read.

  Return Values:
        TRUE - A byte was successfully read
        FALSE - No data remained in the read buffer
  ***************************************************************************/
BOOL UDPGet(BYTE *v)
{
        // Make sure that there is data to return
    if((wGetOffset >= UDPRxCount) || (SocketWithRxData != activeUDPSocket))
        return FALSE;

    *v = MACGet();
    wGetOffset++;

    return TRUE;
}


/*****************************************************************************
  Function:
        WORD UDPGetArray(BYTE *cData, WORD wDataLen)

  Summary:
        Reads an array of bytes from the currently active socket.
        
  Description:
        This function reads an array of bytes from the currently active UDP socket, 
        while decrementing the remaining bytes available. UDPIsGetReady should be 
        used before calling this function to specify the currently active socket.

  Precondition:
        UDPIsGetReady() was previously called to specify the current socket.

  Parameters:
        cData - The buffer to receive the bytes being read.
        wDateLen - Number of bytes to be read from the socket.
        
  Returns:
        The number of bytes successfully read from the UDP buffer.  If this
        value is less than wDataLen, then the buffer was emptied and no more 
        data is available.
  ***************************************************************************/
WORD UDPGetArray(BYTE *cData, WORD wDataLen)
{
        WORD wBytesAvailable;
        
        // Make sure that there is data to return
    if((wGetOffset >= UDPRxCount) || (SocketWithRxData != activeUDPSocket))
                return 0;

        // Make sure we don't try to read more data than exists
        wBytesAvailable = UDPRxCount - wGetOffset;
        if(wBytesAvailable < wDataLen)
                wDataLen = wBytesAvailable;

        wDataLen = MACGetArray(cData, wDataLen);
    wGetOffset += wDataLen;

    return wDataLen;
}

/*****************************************************************************
  Function:
        void UDPDiscard(void)

  Summary:
        Discards any remaining RX data from a UDP socket.
        
  Description:
        This function discards any remaining received data in the currently 
        active UDP socket.

  Precondition:
        UDPIsGetReady() was previously called to select the currently active
        socket.

  Parameters:
        None
        
  Returns:
        None

  Remarks:
        It is safe to call this function more than is necessary.  If no data is
        available, this function does nothing.
  ***************************************************************************/
void UDPDiscard(void)
{
        if(!Flags.bWasDiscarded)
        {
                MACDiscardRx();
                UDPRxCount = 0;
                SocketWithRxData = INVALID_UDP_SOCKET;
                Flags.bWasDiscarded = 1;
        }
}



/****************************************************************************
  Section:
        Data Processing Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        BOOL UDPProcess(NODE_INFO *remoteNode, IP_ADDR *localIP, WORD len)

  Summary:
        Handles an incoming UDP segment.
        
  Description:
        This function handles an incoming UDP segment to determine if it is 
        acceptable and should be handed to one of the stack applications for
        processing.

  Precondition:
        UDPInit() has been called an a UDP segment is ready in the MAC buffer.

  Parameters:
        remoteNode - The remote node that sent this segment.
        localIP - The destination IP address for this segment.
        len - Total length of the UDP segment.
        
  Return Values:
        TRUE - A valid packet is waiting and the stack applications should be
                called to handle it.
        FALSE - The packet was discarded.
  ***************************************************************************/
BOOL UDPProcess(NODE_INFO *remoteNode, IP_ADDR *localIP, WORD len)
{
    UDP_HEADER          h;
    UDP_SOCKET          s;
    PSEUDO_HEADER       pseudoHeader;
    DWORD_VAL           checksums;

        UDPRxCount = 0;

    // Retrieve UDP header.
    MACGetArray((BYTE*)&h, sizeof(h));

    h.SourcePort        = swaps(h.SourcePort);
    h.DestinationPort   = swaps(h.DestinationPort);
    h.Length            = swaps(h.Length) - sizeof(UDP_HEADER);

        // See if we need to validate the checksum field (0x0000 is disabled)
        if(h.Checksum)
        {
            // Calculate IP pseudoheader checksum.
            pseudoHeader.SourceAddress          = remoteNode->IPAddr;
            pseudoHeader.DestAddress.Val        = localIP->Val;
            pseudoHeader.Zero                           = 0x0;
            pseudoHeader.Protocol                       = IP_PROT_UDP;
            pseudoHeader.Length                         = len;

            SwapPseudoHeader(pseudoHeader);
        
            checksums.w[0] = ~CalcIPChecksum((BYTE*)&pseudoHeader,
                                            sizeof(pseudoHeader));
        
        
            // Now calculate UDP packet checksum in NIC RAM -- should match pseudoHeader
            IPSetRxBuffer(0);
            checksums.w[1] = CalcIPBufferChecksum(len);
        
            if(checksums.w[0] != checksums.w[1])
            {
                MACDiscardRx();
                return FALSE;
            }
        }

    s = FindMatchingSocket(&h, remoteNode, localIP);
    if(s == INVALID_UDP_SOCKET)
    {
        // If there is no matching socket, There is no one to handle
        // this data.  Discard it.
        MACDiscardRx();
                return FALSE;
    }
    else
    {
                SocketWithRxData = s;
        UDPRxCount = h.Length;
        Flags.bFirstRead = 1;
                Flags.bWasDiscarded = 0;
    }


    return TRUE;
}

/*****************************************************************************
  Function:
        static UDP_SOCKET FindMatchingSocket(UDP_HEADER *h, NODE_INFO *remoteNode,
                                                IP_ADDR *localIP)

  Summary:
        Matches an incoming UDP segment to a currently active socket.
        
  Description:
        This function attempts to match an incoming UDP segment to a currently
        active socket for processing.

  Precondition:
        UDP segment header and IP header have both been retrieved.

  Parameters:
        h - The UDP header that was received.
        remoteNode - IP and MAC of the remote node that sent this segment.
        localIP - IP address that this segment was destined for.
        
  Returns:
        A UDP_SOCKET handle of a matching socket, or INVALID_UDP_SOCKET when no
        match could be made.
  ***************************************************************************/
static UDP_SOCKET FindMatchingSocket(UDP_HEADER *h,
                                     NODE_INFO *remoteNode,
                                     IP_ADDR *localIP)
{
    UDP_SOCKET s;
    UDP_SOCKET partialMatch;
    UDP_SOCKET_INFO *p;

    partialMatch = INVALID_UDP_SOCKET;

    p = UDPSocketInfo;
    for ( s = 0; s < MAX_UDP_SOCKETS; s++ )
    {
        // This packet is said to be matching with current socket:
        // 1. If its destination port matches with our local port and
        // 2. Packet source IP address matches with socket remote IP address.
        //    OR this socket had transmitted packet with destination address as broadcast (subnet or limited broadcast).
        if ( p->localPort == h->DestinationPort )
        {
            if(p->remotePort == h->SourcePort)
            {
                if( (p->remoteNode.IPAddr.Val == remoteNode->IPAddr.Val) ||
                    (localIP->Val == 0xFFFFFFFFul) || 
                                        (localIP->Val == (AppConfig.MyIPAddr.Val | (~AppConfig.MyMask.Val))))
                {
                    return s;
                }
#ifdef STACK_USE_ZEROCONF_MDNS_SD
                /* Multicast Support in UDP Layer for mDNS.
                 * mDNS- Multicast DNS for Zeroconf protocol.
                 * Multicast address used by mDNS: 224.0.0.251 : 5353
                 * second check with self MAC-address is to
                 * suppress Loop-Back packets */
                else if (localIP->Val == 0xFB0000E0ul)
                {
                    if(remoteNode->IPAddr.Val!= AppConfig.MyIPAddr.Val)
                        return s;
                    else
                        return INVALID_UDP_SOCKET;                                           
                }
#endif
            }

            partialMatch = s;
        }
        p++;
    }

    if ( partialMatch != INVALID_UDP_SOCKET )
    {
        p = &UDPSocketInfo[partialMatch];

        memcpy((void*)&p->remoteNode,
                (const void*)remoteNode, sizeof(p->remoteNode) );

        p->remotePort = h->SourcePort;
    }
    return partialMatch;
}


#endif //#if defined(STACK_USE_UDP)
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3