mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-27 22:24:30 +08:00
51723c5581
While doing DHCP the interface IP is set to 0.0.0.0. This causes the check in net.c on dst_ip to be effectively skipped, and all IP datagrams are accepted up the IP stack. In the case of an ICMP_ECHO_REQUEST for the matching MAC address (regardless of destination IP), the result is that an ICMP_ECHO_REPLY is sent. The source address of the ICMP_ECHO_REPLY is 0.0.0.0, which is an illegal source address. This can happen in common practice with the following sequence: DHCP (U-Boot or OS) acquires IP address 10.0.0.1 System reboots U-Boot starts DHCP and send DHCP DISCOVER DHCP server decides to OFFER 10.0.0.1 again (perhaps because of existing lease or manual configuration) DHCP server tries to PING 10.0.0.1 to see if anyone is squatting on it DHCP server still has our MAC address in its ARP table for 10.0.0.1 U-Boot receives PING, and responds with an illegal source address This may further result in a the DHCP server seeing the response as confirmation that someone is squatting on 10.0.0.1, and picking a new IP address from the pool to try again Signed-off-by: David Rivshin <drivshin@allworx.com>
120 lines
2.8 KiB
C
120 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copied from Linux Monitor (LiMon) - Networking.
|
|
*
|
|
* Copyright 1994 - 2000 Neil Russell.
|
|
* (See License)
|
|
* Copyright 2000 Roland Borde
|
|
* Copyright 2000 Paolo Scaffardi
|
|
* Copyright 2000-2002 Wolfgang Denk, wd@denx.de
|
|
*/
|
|
|
|
#include "ping.h"
|
|
#include "arp.h"
|
|
#include <log.h>
|
|
#include <net.h>
|
|
|
|
static ushort ping_seq_number;
|
|
|
|
/* The ip address to ping */
|
|
struct in_addr net_ping_ip;
|
|
|
|
static void set_icmp_header(uchar *pkt, struct in_addr dest)
|
|
{
|
|
/*
|
|
* Construct an IP and ICMP header.
|
|
*/
|
|
struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + IP_HDR_SIZE);
|
|
|
|
net_set_ip_header(pkt, dest, net_ip, IP_ICMP_HDR_SIZE, IPPROTO_ICMP);
|
|
|
|
icmp->type = ICMP_ECHO_REQUEST;
|
|
icmp->code = 0;
|
|
icmp->checksum = 0;
|
|
icmp->un.echo.id = 0;
|
|
icmp->un.echo.sequence = htons(ping_seq_number++);
|
|
icmp->checksum = compute_ip_checksum(icmp, ICMP_HDR_SIZE);
|
|
}
|
|
|
|
static int ping_send(void)
|
|
{
|
|
uchar *pkt;
|
|
int eth_hdr_size;
|
|
|
|
/* XXX always send arp request */
|
|
|
|
debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &net_ping_ip);
|
|
|
|
net_arp_wait_packet_ip = net_ping_ip;
|
|
|
|
eth_hdr_size = net_set_ether(net_tx_packet, net_null_ethaddr, PROT_IP);
|
|
pkt = (uchar *)net_tx_packet + eth_hdr_size;
|
|
|
|
set_icmp_header(pkt, net_ping_ip);
|
|
|
|
/* size of the waiting packet */
|
|
arp_wait_tx_packet_size = eth_hdr_size + IP_ICMP_HDR_SIZE;
|
|
|
|
/* and do the ARP request */
|
|
arp_wait_try = 1;
|
|
arp_wait_timer_start = get_timer(0);
|
|
arp_request();
|
|
return 1; /* waiting */
|
|
}
|
|
|
|
static void ping_timeout_handler(void)
|
|
{
|
|
eth_halt();
|
|
net_set_state(NETLOOP_FAIL); /* we did not get the reply */
|
|
}
|
|
|
|
void ping_start(void)
|
|
{
|
|
printf("Using %s device\n", eth_get_name());
|
|
net_set_timeout_handler(10000UL, ping_timeout_handler);
|
|
|
|
ping_send();
|
|
}
|
|
|
|
void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
|
|
{
|
|
struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
|
|
struct in_addr src_ip;
|
|
int eth_hdr_size;
|
|
uchar *tx_packet;
|
|
|
|
switch (icmph->type) {
|
|
case ICMP_ECHO_REPLY:
|
|
src_ip = net_read_ip((void *)&ip->ip_src);
|
|
if (src_ip.s_addr == net_ping_ip.s_addr)
|
|
net_set_state(NETLOOP_SUCCESS);
|
|
return;
|
|
case ICMP_ECHO_REQUEST:
|
|
if (net_ip.s_addr == 0)
|
|
return;
|
|
|
|
eth_hdr_size = net_update_ether(et, et->et_src, PROT_IP);
|
|
|
|
debug_cond(DEBUG_DEV_PKT,
|
|
"Got ICMP ECHO REQUEST, return %d bytes\n",
|
|
eth_hdr_size + len);
|
|
|
|
ip->ip_sum = 0;
|
|
ip->ip_off = 0;
|
|
net_copy_ip((void *)&ip->ip_dst, &ip->ip_src);
|
|
net_copy_ip((void *)&ip->ip_src, &net_ip);
|
|
ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE);
|
|
|
|
icmph->type = ICMP_ECHO_REPLY;
|
|
icmph->checksum = 0;
|
|
icmph->checksum = compute_ip_checksum(icmph, len - IP_HDR_SIZE);
|
|
|
|
tx_packet = net_get_async_tx_pkt_buf();
|
|
memcpy(tx_packet, et, eth_hdr_size + len);
|
|
net_send_packet(tx_packet, eth_hdr_size + len);
|
|
return;
|
|
/* default:
|
|
return;*/
|
|
}
|
|
}
|