xref: /openbmc/u-boot/net/ping.c (revision 22f6e99d5b0c54758646334c1153737a5585bd57)
1 /*
2  *	Copied from Linux Monitor (LiMon) - Networking.
3  *
4  *	Copyright 1994 - 2000 Neil Russell.
5  *	(See License)
6  *	Copyright 2000 Roland Borde
7  *	Copyright 2000 Paolo Scaffardi
8  *	Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  */
10 
11 #include "ping.h"
12 #include "arp.h"
13 
14 static ushort PingSeqNo;
15 
16 /* The ip address to ping */
17 IPaddr_t NetPingIP;
18 
19 static void set_icmp_header(uchar *pkt, IPaddr_t dest)
20 {
21 	/*
22 	 *	Construct an IP and ICMP header.
23 	 */
24 	struct ip_hdr *ip = (struct ip_hdr *)pkt;
25 	struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + IP_HDR_SIZE);
26 
27 	net_set_ip_header(pkt, dest, NetOurIP);
28 
29 	ip->ip_len   = htons(IP_ICMP_HDR_SIZE);
30 	ip->ip_p     = IPPROTO_ICMP;
31 	ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE >> 1);
32 
33 	icmp->type = ICMP_ECHO_REQUEST;
34 	icmp->code = 0;
35 	icmp->checksum = 0;
36 	icmp->un.echo.id = 0;
37 	icmp->un.echo.sequence = htons(PingSeqNo++);
38 	icmp->checksum = ~NetCksum((uchar *)icmp, ICMP_HDR_SIZE	>> 1);
39 }
40 
41 static int ping_send(void)
42 {
43 	static uchar mac[6];
44 	uchar *pkt;
45 	int eth_hdr_size;
46 
47 	/* XXX always send arp request */
48 
49 	memcpy(mac, NetEtherNullAddr, 6);
50 
51 	debug("sending ARP for %pI4\n", &NetPingIP);
52 
53 	NetArpWaitPacketIP = NetPingIP;
54 	NetArpWaitPacketMAC = mac;
55 
56 	pkt = NetArpWaitTxPacket;
57 	eth_hdr_size = NetSetEther(pkt, mac, PROT_IP);
58 	pkt += eth_hdr_size;
59 
60 	set_icmp_header(pkt, NetPingIP);
61 
62 	/* size of the waiting packet */
63 	NetArpWaitTxPacketSize = eth_hdr_size + IP_ICMP_HDR_SIZE;
64 
65 	/* and do the ARP request */
66 	NetArpWaitTry = 1;
67 	NetArpWaitTimerStart = get_timer(0);
68 	ArpRequest();
69 	return 1;	/* waiting */
70 }
71 
72 static void ping_timeout(void)
73 {
74 	eth_halt();
75 	net_set_state(NETLOOP_FAIL);	/* we did not get the reply */
76 }
77 
78 void ping_start(void)
79 {
80 	printf("Using %s device\n", eth_get_name());
81 	NetSetTimeout(10000UL, ping_timeout);
82 
83 	ping_send();
84 }
85 
86 void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
87 {
88 	struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
89 	IPaddr_t src_ip;
90 
91 	switch (icmph->type) {
92 	case ICMP_ECHO_REPLY:
93 		src_ip = NetReadIP((void *)&ip->ip_src);
94 		if (src_ip == NetPingIP)
95 			net_set_state(NETLOOP_SUCCESS);
96 		return;
97 	case ICMP_ECHO_REQUEST:
98 		debug("Got ICMP ECHO REQUEST, return "
99 			"%d bytes\n", ETHER_HDR_SIZE + len);
100 
101 		memcpy(&et->et_dest[0], &et->et_src[0], 6);
102 		memcpy(&et->et_src[0], NetOurEther, 6);
103 
104 		ip->ip_sum = 0;
105 		ip->ip_off = 0;
106 		NetCopyIP((void *)&ip->ip_dst, &ip->ip_src);
107 		NetCopyIP((void *)&ip->ip_src, &NetOurIP);
108 		ip->ip_sum = ~NetCksum((uchar *)ip,
109 				       IP_HDR_SIZE >> 1);
110 
111 		icmph->type = ICMP_ECHO_REPLY;
112 		icmph->checksum = 0;
113 		icmph->checksum = ~NetCksum((uchar *)icmph,
114 			(len - IP_HDR_SIZE) >> 1);
115 		NetSendPacket((uchar *)et, ETHER_HDR_SIZE + len);
116 		return;
117 /*	default:
118 		return;*/
119 	}
120 }
121