/****************************************************************************** * * Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * @file xemaclite_ping_req_example.c * * This file contains a EmacLite Ping request example in polled mode. This * example will generate a ping request for the specified IP address. * * @note * * The local IP address is set to 172.16.63.121. User needs to update * LocalIpAddr variable with a free IP address based on the network on which * this example is to be run. * * The Destination IP address is set to 172.16.63.61. User needs to update * DestIpAddress variable with any valid IP address based on the network on which * this example is to be run. * * The local MAC address is set to 0x000A35030201. User can update LocalMacAddr * variable with a valid MAC address. The first three bytes contains * the manufacture ID. 0x000A35 is XILINX manufacture ID. * * This program will generate the specified number of ping request packets as * defined in "NUM_OF_PING_REQ_PKTS". * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- * 1.00a ktn 27/08/08 First release * 3.00a ktn 10/22/09 Updated example to use the macros that have been changed * in the driver to remove _m from the name of the macro. * 3.01a ktn 08/06/10 Updated the example to support little endian MicroBlaze. * ** *****************************************************************************/ /***************************** Include Files *********************************/ #include "xparameters.h" #include "xstatus.h" #include "xemaclite.h" #include "stdio.h" #include "xil_io.h" /************************** Constant Definitions *****************************/ /* * The following constants map to the XPAR parameters created in the * xparameters.h file. They are defined here such that a user can easily * change all the needed parameters in one place. */ #define EMAC_DEVICE_ID XPAR_EMACLITE_0_DEVICE_ID /* * Change this parameter to limit the number of ping requests sent by this * program. */ #define NUM_OF_PING_REQ_PKTS 100 /* Number of ping req it generates */ #define ECHO_REPLY 0x00 /* Echo reply */ #define HW_TYPE 0x01 /* Hardware type (10/100 Mbps) */ #define ARP_REQUEST 0x01 /* ARP Request bits in Rx packet */ #define ARP_REPLY 0x02 /* ARP status bits indicating reply */ #define IDEN_NUM 0x02 /* ICMP identifier number */ #define IP_VERSION 0x0604 /* IP version ipv4/ipv6 */ #define BROADCAST_ADDR 0xFFFF /* Broadcast Address */ #define CORRECT_CHECKSUM_VALUE 0xFFFF /* Correct checksum value */ #define ARP_REQ_PKT_SIZE 0x2A /* ARP request packet size */ #define ICMP_PKT_SIZE 0x4A /* ICMP packet length 74 Bytes including Src and dest MAC Add */ #define IP_ADDR_SIZE 4 /* IP Address size in Bytes */ #define NUM_RX_PACK_CHECK_REQ 10 /* Max num of Rx pack to be checked before sending another request */ #define NUM_PACK_CHECK_RX_PACK 100 /* Max number of pack to be checked before to identify a Rx packet */ #define DELAY 5000000 /* Used to introduce delay */ /* * Definitions for the locations and length of some of the fields in a * IP packet. The lengths are defined in Half-Words (2 bytes). */ #define SRC_MAC_ADDR_LOC 3 /* Src MAC address location */ #define MAC_ADDR_LEN 3 /* MAC address length */ #define ETHER_PROTO_TYPE_LOC 6 /* Ethernet Proto type loc */ #define IP_ADDR_LEN 2 /* Size of IP address */ #define IP_START_LOC 7 /* IP header start location */ #define IP_HEADER_INFO_LEN 7 /* IP header information length */ #define IP_HEADER_LEN 10 /* IP header length */ #define IP_CHECKSUM_LOC 12 /* IP header checksum location */ #define IP_REQ_SRC_IP_LOC 13 /* Src IP add loc of ICMP req */ #define IP_REQ_DEST_IP_LOC 15 /* Dest IP add loc of ICMP req */ #define ICMP_KNOWN_DATA_LEN 16 /* ICMP known data length */ #define ICMP_ECHO_FIELD_LOC 17 /* Echo field loc */ #define ICMP_DATA_START_LOC 17 /* Data field start location */ #define ICMP_DATA_LEN 18 /* ICMP data length */ #define ICMP_DATA_CHECKSUM_LOC 18 /* ICMP data checksum location */ #define ICMP_IDEN_FIELD_LOC 19 /* Identifier field loc */ #define ICMP_DATA_LOC 19 /* ICMP data loc including identifier number and sequence number */ #define ICMP_SEQ_NO_LOC 20 /* sequence number location */ #define ICMP_DATA_FIELD_LEN 20 /* Data field length */ #define ICMP_KNOWN_DATA_LOC 21 /* ICMP known data start loc */ #define ARP_REQ_STATUS_LOC 10 /* ARP request loc */ #define ARP_REQ_SRC_IP_LOC 14 /* Src IP add loc of ARP req Packet */ /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ static int EmacLitePingReqExample(u16 DeviceId); static void SendArpReqFrame(XEmacLite *InstancePtr); static void SendEchoReqFrame(XEmacLite *InstancePtr); static int ProcessRecvFrame(XEmacLite *InstancePtr); static u16 CheckSumCalculation(u16 *RxFramePtr16, int StartLoc, int Length); static int CompareData(u16 *LhsPtr, u16 *RhsPtr, int LhsLoc, int RhsLoc, int Count); /************************** Variable Definitions *****************************/ /* * Set up a local MAC address. */ static u8 LocalMacAddr[XEL_MAC_ADDR_SIZE] = { 0x00, 0x0A, 0x35, 0x03, 0x02, 0x01 }; /* * The IP address was set to 172.16.63.121. User need to set a free IP address * based on the network on which this example is to be run. */ static u8 LocalIpAddress[IP_ADDR_SIZE] = { 172, 16, 63, 121 }; /* * Set up a Destination IP address. Currently it is set to 172.16.63.61. */ static u8 DestIpAddress[IP_ADDR_SIZE] = { 172, 16, 63, 61 }; static u16 DestMacAddr[MAC_ADDR_LEN]; /* Destination MAC Address */ static XEmacLite EmacLiteInstance; /* Instance of the EmacLite driver */ /* * Known data transmitted in Echo request. */ u16 IcmpData[ICMP_KNOWN_DATA_LEN] = { 0x6162, 0x6364, 0x6566, 0x6768, 0x696A, 0x6B6C, 0x6D6E, 0x6F70, 0x7172, 0x7374, 0x7576, 0x7761, 0x6263, 0x6465, 0x6667, 0x6869 }; /* * IP header information -- each field has its own significance. * Icmp type, ipv4 typelength, packet length, identification field * Fragment type, time to live and ICM, checksum. */ u16 IpHeaderInfo[IP_HEADER_INFO_LEN] = { 0x0800, 0x4500, 0x003C, 0x5566, 0x0000, 0x8001, 0x0000 }; /* * Buffers used for Transmission and Reception of Packets. These are declared as * global so that they are not a part of the stack. */ static u8 RxFrame[XEL_MAX_FRAME_SIZE]; static u8 TxFrame[XEL_MAX_FRAME_SIZE]; /* * Variable used to indicate the length of the received frame. */ u32 RecvFrameLength; /* * Variable used to indicate the sequence number of the ICMP(echo) packet. */ int SeqNum; /* * Variable used to indicate the number of ping request packets to be send. */ int NumOfPingReqPkts; /****************************************************************************/ /** * * This function is the main function of the Ping Request example in polled mode. * * @param None. * * @return XST_FAILURE to indicate failure, otherwise it will return * XST_SUCCESS after sending specified number of packets as * defined in "NUM_OF_PING_REQ_PKTS" . * * @note None. * *****************************************************************************/ int main() { int Status; /* * Run the EmacLite Ping request example. */ Status = EmacLitePingReqExample(EMAC_DEVICE_ID); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /*****************************************************************************/ /** * * The entry point for the EmacLite driver to ping request example in polled * mode. This function will generate specified number of request packets as * defined in "NUM_OF_PING_REQ_PKTS. * * @param DeviceId is device ID of the XEmacLite Device. * * @return XST_FAILURE to indicate failure, otherwise it will return * XST_SUCCESS. * * @note None. * ******************************************************************************/ static int EmacLitePingReqExample(u16 DeviceId) { int Status; int Index; int Count; int EchoReplyStatus; XEmacLite_Config *ConfigPtr; XEmacLite *EmacLiteInstPtr = &EmacLiteInstance; SeqNum = 0; RecvFrameLength = 0; EchoReplyStatus = XST_FAILURE; NumOfPingReqPkts = NUM_OF_PING_REQ_PKTS; /* * Initialize the EmacLite device. */ ConfigPtr = XEmacLite_LookupConfig(DeviceId); if (ConfigPtr == NULL) { return XST_FAILURE; } Status = XEmacLite_CfgInitialize(EmacLiteInstPtr, ConfigPtr, ConfigPtr->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Set the MAC address. */ XEmacLite_SetMacAddress(EmacLiteInstPtr, LocalMacAddr); /* * Empty any existing receive frames. */ XEmacLite_FlushReceive(EmacLiteInstPtr); while (NumOfPingReqPkts--) { /* * Introduce delay. */ Count = DELAY; while (Count--) { } /* * Send an ARP or an ICMP packet based on receive packet. */ if (SeqNum == 0) { SendArpReqFrame(EmacLiteInstPtr); } else { SendEchoReqFrame(EmacLiteInstPtr); } /* * Check next 10 packets for the correct reply. */ Index = NUM_RX_PACK_CHECK_REQ; while (Index--) { /* * Wait for a Receive packet. */ Count = NUM_PACK_CHECK_RX_PACK; while (RecvFrameLength == 0) { RecvFrameLength = XEmacLite_Recv( EmacLiteInstPtr, (u8 *)RxFrame); /* * To avoid infinite loop when no packet is * received. */ if (Count-- == 0) { break; } } /* * Process the Receive frame. */ if (RecvFrameLength != 0) { EchoReplyStatus = ProcessRecvFrame( EmacLiteInstPtr); } RecvFrameLength = 0; /* * Comes out of loop when an echo reply packet is * received. */ if (EchoReplyStatus == XST_SUCCESS) { break; } } /* * If no echo reply packet is received, it reports * request timed out. */ if (EchoReplyStatus == XST_FAILURE) { xil_printf("Packet No: %d", NUM_OF_PING_REQ_PKTS - NumOfPingReqPkts); xil_printf(" Seq NO %d Request timed out\r\n", SeqNum); } } return XST_SUCCESS; } /*****************************************************************************/ /** * * This function will send a ARP request packet. * * @param InstancePtr is a pointer to the instance of the EmacLite. * * @return None. * * @note None. * ******************************************************************************/ static void SendArpReqFrame(XEmacLite *InstancePtr) { u16 *TempPtr; u16 *TxFramePtr; u32 NextTxBuffBaseAddr; int Index; TxFramePtr = (u16 *)TxFrame; /* * Determine the next expected transmit buffer base address. */ NextTxBuffBaseAddr = XEmacLite_NextTransmitAddr(InstancePtr); /* * Add broadcast address. */ Index = MAC_ADDR_LEN; while (Index--) { *TxFramePtr++ = BROADCAST_ADDR; } /* * Add local MAC address. */ Index = 0; TempPtr = (u16 *)LocalMacAddr; while (Index < MAC_ADDR_LEN) { *TxFramePtr++ = *(TempPtr + Index); Index++; } /* * Add * - Ethernet proto type. * - Hardware Type * - Protocol IP Type * - IP version (IPv6/IPv4) * - ARP Request */ *TxFramePtr++ = Xil_Htons(XEL_ETHER_PROTO_TYPE_ARP); *TxFramePtr++ = Xil_Htons(HW_TYPE); *TxFramePtr++ = Xil_Htons(XEL_ETHER_PROTO_TYPE_IP); *TxFramePtr++ = Xil_Htons(IP_VERSION); *TxFramePtr++ = Xil_Htons(ARP_REQUEST); /* * Add local MAC address. */ Index = 0; TempPtr = (u16 *)LocalMacAddr; while (Index < MAC_ADDR_LEN) { *TxFramePtr++ = *(TempPtr + Index); Index++; } /* * Add local IP address. */ Index = 0; TempPtr = (u16 *)LocalIpAddress; while (Index < IP_ADDR_LEN) { *TxFramePtr++ = *(TempPtr + Index); Index++; } /* * Fills 6 bytes of information with zeros as per protocol. */ Index = 0; while (Index < 3) { *TxFramePtr++ = 0x0000; Index++; } /* * Add Destination IP address. */ Index = 0; TempPtr = (u16 *)DestIpAddress; while (Index < IP_ADDR_LEN) { *TxFramePtr++ = *(TempPtr + Index); Index++; } /* * Transmit the Frame. */ XEmacLite_Send(InstancePtr, (u8 *)&TxFrame, ARP_REQ_PKT_SIZE); } /*****************************************************************************/ /** * * This function will send a Echo request packet. * * @param InstancePtr is a pointer to the instance of the EmacLite. * * @return None. * * @note None. * ******************************************************************************/ static void SendEchoReqFrame(XEmacLite *InstancePtr) { u16 *TempPtr; u16 *TxFramePtr; u16 *RxFramePtr; u16 CheckSum; u32 NextTxBuffBaseAddr; int Index; TxFramePtr = (u16 *)TxFrame; RxFramePtr = (u16 *)RxFrame; /* * Determine the next expected transmit buffer base address. */ NextTxBuffBaseAddr = XEmacLite_NextTransmitAddr(InstancePtr); /* * Add Destination MAC Address. */ Index = MAC_ADDR_LEN; while (Index--) { *(TxFramePtr + Index) = *(DestMacAddr + Index); } /* * Add Source MAC Address. */ Index = MAC_ADDR_LEN; TempPtr = (u16 *)LocalMacAddr; while (Index--) { *(TxFramePtr + (Index + SRC_MAC_ADDR_LOC )) = *(TempPtr + Index); } /* * Add IP header information. */ Index = IP_START_LOC; while (Index--) { *(TxFramePtr + (Index + ETHER_PROTO_TYPE_LOC )) = Xil_Htons(*(IpHeaderInfo + Index)); } /* * Add Source IP address. */ Index = IP_ADDR_LEN; TempPtr = (u16 *)LocalIpAddress; while (Index--) { *(TxFramePtr + (Index + IP_REQ_SRC_IP_LOC )) = *(TempPtr + Index); } /* * Add Destination IP address. */ Index = IP_ADDR_LEN; TempPtr = (u16 *)DestIpAddress; while (Index--) { *(TxFramePtr + (Index + IP_REQ_DEST_IP_LOC )) = *(TempPtr + Index); } /* * Checksum is calculated for IP field and added in the frame. */ CheckSum = CheckSumCalculation((u16 *)TxFrame, IP_START_LOC, IP_HEADER_LEN); CheckSum = ~CheckSum; *(TxFramePtr + IP_CHECKSUM_LOC) = Xil_Htons(CheckSum); /* * Add echo field information. */ *(TxFramePtr + ICMP_ECHO_FIELD_LOC) = Xil_Htons(XEL_ETHER_PROTO_TYPE_IP); /* * Checksum value is initialized to zeros. */ *(TxFramePtr + ICMP_DATA_LEN) = 0x0000; /* * Add identifier and sequence number to the frame. */ *(TxFramePtr + ICMP_IDEN_FIELD_LOC) = (IDEN_NUM); *(TxFramePtr + (ICMP_IDEN_FIELD_LOC + 1)) = Xil_Htons((u16)(++SeqNum)); /* * Add known data to the frame. */ Index = ICMP_KNOWN_DATA_LEN; while (Index--) { *(TxFramePtr + (Index + ICMP_KNOWN_DATA_LOC)) = Xil_Htons(*(IcmpData + Index)); } /* * Checksum is calculated for Data Field and added in the frame. */ CheckSum = CheckSumCalculation((u16 *)TxFrame, ICMP_DATA_START_LOC, ICMP_DATA_FIELD_LEN ); CheckSum = ~CheckSum; *(TxFramePtr + ICMP_DATA_CHECKSUM_LOC) = Xil_Htons(CheckSum); /* * Transmit the Frame. */ XEmacLite_Send(InstancePtr, (u8 *)&TxFrame, ICMP_PKT_SIZE); } /*****************************************************************************/ /** * * This function will process the received packet. This function sends * the echo request packet based on the ARP reply packet. * * @param InstancePtr is a pointer to the instance of the EmacLite. * * @return XST_SUCCESS is returned when an echo reply is received. * Otherwise, XST_FAILURE is returned. * * @note This assumes MAC does not strip padding or CRC. * ******************************************************************************/ static int ProcessRecvFrame(XEmacLite *InstancePtr) { u16 *RxFramePtr; u16 *TempPtr; u16 CheckSum; int Index; int Match = 0; int DataWrong = 0; RxFramePtr = (u16 *)RxFrame; TempPtr = (u16 *)LocalMacAddr; /* * Check Dest Mac address of the packet with the LocalMac address. */ Match = CompareData(RxFramePtr, TempPtr, 0, 0, MAC_ADDR_LEN); if (Match == XST_SUCCESS) { /* * Check ARP type. */ if (Xil_Ntohs(*(RxFramePtr + ETHER_PROTO_TYPE_LOC)) == XEL_ETHER_PROTO_TYPE_ARP ) { /* * Check ARP status. */ if (Xil_Ntohs(*(RxFramePtr + ARP_REQ_STATUS_LOC)) == ARP_REPLY) { /* * Check destination IP address with * packet's source IP address. */ TempPtr = (u16 *)DestIpAddress; Match = CompareData(RxFramePtr, TempPtr, ARP_REQ_SRC_IP_LOC, 0, IP_ADDR_LEN); if (Match == XST_SUCCESS) { /* * Copy src Mac address of the received * packet. */ Index = MAC_ADDR_LEN; TempPtr = (u16 *)DestMacAddr; while (Index--) { *(TempPtr + Index) = *(RxFramePtr + (SRC_MAC_ADDR_LOC + Index)); } /* * Send Echo request packet. */ SendEchoReqFrame(InstancePtr); } } } /* * Check for IP type. */ else if (Xil_Ntohs(*(RxFramePtr + ETHER_PROTO_TYPE_LOC)) == XEL_ETHER_PROTO_TYPE_IP) { /* * Calculate checksum. */ CheckSum = CheckSumCalculation(RxFramePtr, ICMP_DATA_START_LOC, ICMP_DATA_FIELD_LEN); /* * Verify checksum, echo reply, identifier number and * sequence number of the received packet. */ if ((CheckSum == CORRECT_CHECKSUM_VALUE) && (Xil_Ntohs(*(RxFramePtr + ICMP_ECHO_FIELD_LOC)) == ECHO_REPLY) && (Xil_Ntohs(*(RxFramePtr + ICMP_IDEN_FIELD_LOC)) == IDEN_NUM) && (Xil_Ntohs(*(RxFramePtr + (ICMP_SEQ_NO_LOC))) == SeqNum)) { /* * Verify data in the received packet with known * data. */ TempPtr = IcmpData; Match = CompareData(RxFramePtr, TempPtr, ICMP_KNOWN_DATA_LOC, 0, ICMP_KNOWN_DATA_LEN); if (Match == XST_FAILURE) { DataWrong = 1; } } if (DataWrong != 1) { xil_printf("Packet No: %d ", NUM_OF_PING_REQ_PKTS - NumOfPingReqPkts); xil_printf("Seq NO %d Echo Packet received\r\n", SeqNum); return XST_SUCCESS; } } } return XST_FAILURE; } /*****************************************************************************/ /** * * This function calculates the checksum and returns a 16 bit result. * * @param RxFramePtr is a 16 bit pointer for the data to which checksum * is to be calculated. * @param StartLoc is the starting location of the data from which the * checksum has to be calculated. * @param Length is the number of halfwords(16 bits) to which checksum is * to be calculated. * * @return It returns a 16 bit checksum value. * * @note This can also be used for calculating checksum. The ones * complement of this return value will give the final checksum. * ******************************************************************************/ static u16 CheckSumCalculation(u16 *RxFramePtr, int StartLoc, int Length) { u32 Sum = 0; u16 CheckSum = 0; int Index; /* * Add all the 16 bit data. */ Index = StartLoc; while (Index < (StartLoc + Length)) { Sum = Sum + Xil_Htons(*(RxFramePtr + Index)); Index++; } /* * Add upper 16 bits to lower 16 bits. */ CheckSum = Sum; Sum = Sum>>16; CheckSum = Sum + CheckSum; return CheckSum; } /*****************************************************************************/ /** * * This function checks the match for the specified number of half words. * * @param LhsPtr is a LHS entity pointer. * @param RhsPtr is a RHS entity pointer. * @param LhsLoc is a LHS entity location. * @param RhsLoc is a RHS entity location. * @param Count is the number of location which has to compared. * * @return XST_SUCCESS is returned when both the entities are same, * otherwise XST_FAILURE is returned. * * @note None. * ******************************************************************************/ static int CompareData(u16 *LhsPtr, u16 *RhsPtr, int LhsLoc, int RhsLoc, int Count) { int Result; while (Count--) { if (*(LhsPtr + LhsLoc + Count) == *(RhsPtr + RhsLoc + Count)) { Result = XST_SUCCESS; } else { Result = XST_FAILURE; break; } } return Result; }