embeddedsw/XilinxProcessorIPLib/drivers/emaclite/examples/xemaclite_ping_req_example.c

806 lines
21 KiB
C
Raw Normal View History

/******************************************************************************
*
* 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".
*
* <pre>
* 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.
*
* </pre>
*
*****************************************************************************/
/***************************** 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;
}