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

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*********************************************************************
 *
 *  Internet Control Message Protocol (ICMP) Server
 *  Module for Microchip TCP/IP Stack
 *   -Provides "ping" diagnostics
 *       -Reference: RFC 792
 *
 *********************************************************************
 * FileName:        ICMP.c
 * Dependencies:    IP, ARP
 * 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
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Howard Schlunder             03/16/07        Original
 ********************************************************************/
#define __ICMP_C

#include "TCPIP Stack/TCPIP.h"

#if defined(STACK_USE_ICMP_SERVER) || defined(STACK_USE_ICMP_CLIENT)

#if defined(STACK_USE_ICMP_CLIENT)

// ICMP Timeout Value
#define ICMP_TIMEOUT    (4ul*TICK_SECOND)

// ICMP Packet Structure
typedef struct
{
        BYTE vType;
        BYTE vCode;
        WORD wChecksum;
        WORD wIdentifier;
        WORD wSequenceNumber;
        WORD wData;
} ICMP_PACKET;

// ICMP Sequence Number
static WORD wICMPSequenceNumber;
// ICMP tick timer variable
static DWORD ICMPTimer;

// ICMP Flag structure
static struct
{
        unsigned char bICMPInUse:1;         // Indicates that the ICMP Client is in use
        unsigned char bReplyValid:1;        // Indicates that a correct Ping response to one of our pings was received
        unsigned char bRemoteHostIsROM:1;   // Indicates that a remote host name was passed as a ROM pointer argument
} ICMPFlags = {0x00};

// ICMP Static Variables
static union
{
        union
        {
                ROM BYTE *szROM;
                BYTE *szRAM;
        } RemoteHost;
        NODE_INFO ICMPRemote;
} StaticVars;

// ICMP State Machine Enumeration
static enum
{
        SM_IDLE = 0,
        SM_DNS_SEND_QUERY,
        SM_DNS_GET_RESPONSE,
        SM_ARP_SEND_QUERY,
        SM_ARP_GET_RESPONSE,
        SM_ICMP_SEND_ECHO_REQUEST,
        SM_ICMP_GET_ECHO_RESPONSE
} ICMPState;

#endif

/*********************************************************************
 * Function:        void ICMPProcess(void)
 *
 * PreCondition:    MAC buffer contains ICMP type packet.
 *
 * Input:           *remote: Pointer to a NODE_INFO structure of the 
 *                                      ping requester
 *                                      len: Count of how many bytes the ping header and 
 *                                      payload are in this IP packet
 *
 * Output:          Generates an echo reply, if requested
 *                                      Validates and sets ICMPFlags.bReplyValid if a 
 *                                      correct ping response to one of ours is received.
 *
 * Side Effects:    None
 *
 * Overview:        None
 *
 * Note:            None
 ********************************************************************/
void ICMPProcess(NODE_INFO *remote, WORD len)
{
        DWORD_VAL dwVal;

    // Obtain the ICMP header Type, Code, and Checksum fields
    MACGetArray((BYTE*)&dwVal, sizeof(dwVal));
        
        // See if this is an ICMP echo (ping) request
        if(dwVal.w[0] == 0x0008u)
        {
                // Validate the checksum using the Microchip MAC's DMA module
                // The checksum data includes the precomputed checksum in the 
                // header, so a valid packet will always have a checksum of 
                // 0x0000 if the packet is not disturbed.
                if(MACCalcRxChecksum(0+sizeof(IP_HEADER), len))
                        return;
        
                // Calculate new Type, Code, and Checksum values
                dwVal.v[0] = 0x00;      // Type: 0 (ICMP echo/ping reply)
                dwVal.v[2] += 8;        // Subtract 0x0800 from the checksum
                if(dwVal.v[2] < 8u)
                {
                        dwVal.v[3]++;
                        if(dwVal.v[3] == 0u)
                                dwVal.v[2]++;
                }
        
            // Wait for TX hardware to become available (finish transmitting 
            // any previous packet)
            while(!IPIsTxReady());

                // Position the write pointer for the next IPPutHeader operation
                // NOTE: do not put this before the IPIsTxReady() call for WF compatbility
            MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER));
                
                // Create IP header in TX memory
                IPPutHeader(remote, IP_PROT_ICMP, len);
        
                // Copy ICMP response into the TX memory
                MACPutArray((BYTE*)&dwVal, sizeof(dwVal));
                MACMemCopyAsync(-1, -1, len-4);
                while(!MACIsMemCopyDone());
        
                // Transmit the echo reply packet
            MACFlush();
        }
#if defined(STACK_USE_ICMP_CLIENT)
        else if(dwVal.w[0] == 0x0000u)  // See if this an ICMP Echo reply to our request
        {
                // Get the sequence number and identifier fields
                MACGetArray((BYTE*)&dwVal, sizeof(dwVal));
                
                // See if the identifier matches the one we sent
                if(dwVal.w[0] != 0xEFBE)        
                        return;
        
                if(dwVal.w[1] != wICMPSequenceNumber)
                        return;

                // Validate the ICMP checksum field
            IPSetRxBuffer(0);
                if(CalcIPBufferChecksum(sizeof(ICMP_PACKET)))   // Two bytes of payload were sent in the echo request
                        return;
                
                // Flag that we received the response and stop the timer ticking
                ICMPFlags.bReplyValid = 1;
                ICMPTimer = TickGet() - ICMPTimer;
        }
#endif
}

#if defined(STACK_USE_ICMP_CLIENT)
/*********************************************************************
 * Function:        void ICMPSendPing(DWORD dwRemoteIP)
 *
 * PreCondition:    ICMPBeginUsage() returned TRUE
 *
 * Input:           dwRemoteIP: IP Address to ping.  Must be stored 
 *                                                              big endian.  Ex. 192.168.0.1 should be
 *                                                              passed as 0xC0A80001.
 *
 * Output:          Begins the process of transmitting an ICMP echo 
 *                                      request.  This normally involves an ARP 
 *                                      resolution procedure first.
 *
 * Side Effects:    None
 *
 * Overview:        None
 *
 * Note:            None
 ********************************************************************/
void ICMPSendPing(DWORD dwRemoteIP)
{
        ICMPFlags.bReplyValid = 0;
        ICMPTimer = TickGet();
        StaticVars.ICMPRemote.IPAddr.Val = dwRemoteIP;
        ICMPState = SM_ARP_SEND_QUERY;
}

#if defined(STACK_USE_DNS)
/*********************************************************************
 * Function:        void ICMPSendPingToHost (BYTE * szRemoteHost)
 *
 * PreCondition:    ICMPBeginUsage() returned TRUE
 *
 * Input:           szRemoteHost: Host name to ping.  Must be stored 
 *                                                                in RAM if being called by PIC18.
 *                                                                Ex. www.microchip.com
 *
 * Output:          Begins the process of transmitting an ICMP echo 
 *                                      request.  This normally involves an ARP 
 *                                      resolution procedure first.
 *
 * Side Effects:    None
 *
 * Overview:        None
 *
 * Note:            None
 ********************************************************************/
void ICMPSendPingToHost(BYTE * szRemoteHost)
{
        ICMPFlags.bReplyValid = 0;
        ICMPTimer = TickGet();
        ICMPFlags.bRemoteHostIsROM = 0;
        StaticVars.RemoteHost.szRAM = szRemoteHost;
        ICMPState = SM_DNS_SEND_QUERY;
}

#if defined(__18CXX)

/*********************************************************************
 * Function:        void ICMPSendPingToHostROM (ROM BYTE * szRemoteHost)
 *
 * PreCondition:    ICMPBeginUsage() returned TRUE
 *
 * Input:           szRemoteHost: Host name to ping.  Must be stored 
 *                                                                in ROM. Should only be called by PIC18.
 *                                                                Ex. www.microchip.com
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Begins the process of transmitting an ICMP echo 
 *                                      request.  This normally involves an ARP 
 *                                      resolution procedure first.
 *
 * Note:            None
 ********************************************************************/
void ICMPSendPingToHostROM(ROM BYTE * szRemoteHost)
{
        ICMPFlags.bReplyValid = 0;
        ICMPTimer = TickGet();
        ICMPFlags.bRemoteHostIsROM = 1;
        StaticVars.RemoteHost.szROM = szRemoteHost;
        ICMPState = SM_DNS_SEND_QUERY;
}

#endif
#endif

/*********************************************************************
 * Function:        LONG ICMPGetReply(void)
 *
 * PreCondition:    ICMPBeginUsage() returned TRUE and ICMPSendPing() 
 *                                      was called
 *
 * Input:           None
 *
 * Output:          -3: Could not resolve hostname (DNS timeout or 
 *                                  hostname invalid)
 *                                      -2: No response received yet
 *                                      -1: Operation timed out (longer than ICMP_TIMEOUT) 
 *                                              has elapsed.
 *                                      >=0: Number of TICKs that elapsed between 
 *                                               initial ICMP transmission and reception of 
 *                                               a valid echo.
 *
 * Side Effects:    None
 *
 * Overview:        None
 *
 * Note:            None
 ********************************************************************/
LONG ICMPGetReply(void)
{
        ICMP_PACKET ICMPPacket;

        switch(ICMPState)
        {
#if defined(STACK_USE_DNS)
                case SM_DNS_SEND_QUERY:
                        // Obtain DNS module ownership
                        if(!DNSBeginUsage())
                                break;
                        
                        // Send DNS query
                        if(ICMPFlags.bRemoteHostIsROM)
                                DNSResolveROM(StaticVars.RemoteHost.szROM, DNS_TYPE_A);
                        else
                                DNSResolve(StaticVars.RemoteHost.szRAM, DNS_TYPE_A);
                        
                        ICMPState = SM_DNS_GET_RESPONSE;
                        break;
                                
                case SM_DNS_GET_RESPONSE:
                        // See if DNS is done, and if so, get the remote IP address
                        if(!DNSIsResolved(&StaticVars.ICMPRemote.IPAddr))
                                break;
                        
                        // Free the DNS module
                        DNSEndUsage();
                        
                        // Return error code if the DNS query failed
                        if(StaticVars.ICMPRemote.IPAddr.Val == 0x00000000ul)
                        {
                                ICMPState = SM_IDLE;
                                return -3;
                        }

                        ICMPState = SM_ARP_SEND_QUERY;  
                        // No break;    
#endif

                case SM_ARP_SEND_QUERY:
                        ARPResolve(&StaticVars.ICMPRemote.IPAddr);
                        ICMPState = SM_ARP_GET_RESPONSE;
                        break;
                        
                case SM_ARP_GET_RESPONSE:
                        // See if the ARP reponse was successfully received
                        if(!ARPIsResolved(&StaticVars.ICMPRemote.IPAddr, &StaticVars.ICMPRemote.MACAddr))
                                break;
                        
                        ICMPState = SM_ICMP_SEND_ECHO_REQUEST;
                        // No break; 
                
                case SM_ICMP_SEND_ECHO_REQUEST:
                    if(!IPIsTxReady())
                        break;

                        // Set up the ping packet
                        ICMPPacket.vType = 0x08;        // 0x08: Echo (ping) request
                        ICMPPacket.vCode = 0x00;
                        ICMPPacket.wChecksum = 0x0000;
                        ICMPPacket.wIdentifier = 0xEFBE;
                        wICMPSequenceNumber++; 
                        ICMPPacket.wSequenceNumber = wICMPSequenceNumber;
                        ICMPPacket.wData = 0x2860;
                        ICMPPacket.wChecksum = CalcIPChecksum((BYTE*)&ICMPPacket, sizeof(ICMPPacket));
                
                        // Record the current time.  This will be used as a basis for 
                        // finding the echo response time, which exludes the ARP and DNS 
                        // steps
                        ICMPTimer = TickGet();

                        // Position the write pointer for the next IPPutHeader operation
                    MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER));
                
                        // Create IP header in TX memory
                        IPPutHeader(&StaticVars.ICMPRemote, IP_PROT_ICMP, sizeof(ICMPPacket));
                        MACPutArray((BYTE*)&ICMPPacket, sizeof(ICMPPacket));
                        MACFlush();

                        // Echo sent, advance state
                        ICMPState = SM_ICMP_GET_ECHO_RESPONSE;
                        break;

                case SM_ICMP_GET_ECHO_RESPONSE:
                        // See if the echo was successfully received
                        if(ICMPFlags.bReplyValid)
                                return (LONG)ICMPTimer;
                
                        break;
                
                // SM_IDLE or illegal/impossible state:
                default:
                        return -1;
        }

        // See if the DNS/ARP/echo request timed out
        if(TickGet() - ICMPTimer > ICMP_TIMEOUT)
        {
                // Free DNS module if we have it in use
                #if defined(STACK_USE_DNS)
                        if(ICMPState == SM_DNS_GET_RESPONSE)
                                DNSEndUsage();
                #endif
                
                // Stop ICMP echo test and return error to caller
                ICMPState = SM_IDLE;
                return -1;
        }

        // Still working.  No response to report yet.
        return -2;
}


/*********************************************************************
 * Function:        BOOL ICMPBeginUsage(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          TRUE: You have successfully gained ownership of 
 *                                                the ICMP client module and can now use the 
 *                                                ICMPSendPing() and ICMPGetReply() functions.
 *                                      FALSE: Some other application is using the ICMP 
 *                                                 client module.  Calling ICMPSendPing() 
 *                                                 will corrupt the other application's ping 
 *                                                 result.
 *
 * Side Effects:    None
 *
 * Overview:        Claims ownership of the ICMP module.
 *
 * Note:            None
 ********************************************************************/
BOOL ICMPBeginUsage(void)
{
        if(ICMPFlags.bICMPInUse)
                return FALSE;

        ICMPFlags.bICMPInUse = TRUE;
        return TRUE;
}


/*********************************************************************
 * Function:        void ICMPEndUsage(void)
 *
 * PreCondition:    ICMPBeginUsage() was called by you and it 
 *                                      returned TRUE.
 *
 * Input:           None
 *
 * Output:          Your ownership of the ICMP module is released.  
 *                                      You can no longer use ICMPSendPing().
 *
 * Side Effects:    None
 *
 * Overview:        Gives up ownership of the ICMP module.
 *
 * Note:            None
 ********************************************************************/
void ICMPEndUsage(void)
{
        ICMPFlags.bICMPInUse = FALSE;
}

#endif //#if defined(STACK_USE_ICMP_CLIENT)

#endif //#if defined(STACK_USE_ICMP_SERVER) || defined(STACK_USE_ICMP_CLIENT)
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3