mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-03 21:48:15 +00:00 
			
		
		
		
	As part of bringing the master branch back in to next, we need to allow for all of these changes to exist here. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
		
			
				
	
	
		
			118 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0+
 | 
						|
/*
 | 
						|
 * Copyright (C) 2013 Allied Telesis Labs NZ
 | 
						|
 * Chris Packham, <judge.packham@gmail.com>
 | 
						|
 *
 | 
						|
 * Copyright (C) 2022 YADRO
 | 
						|
 * Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
 | 
						|
 */
 | 
						|
 | 
						|
/* Simple ping6 implementation */
 | 
						|
 | 
						|
#include <net.h>
 | 
						|
#include <net6.h>
 | 
						|
#include "ndisc.h"
 | 
						|
 | 
						|
static ushort seq_no;
 | 
						|
 | 
						|
/* the ipv6 address to ping */
 | 
						|
struct in6_addr net_ping_ip6;
 | 
						|
 | 
						|
int
 | 
						|
ip6_make_ping(uchar *eth_dst_addr, struct in6_addr *neigh_addr, uchar *pkt)
 | 
						|
{
 | 
						|
	struct echo_msg *msg;
 | 
						|
	u16 len;
 | 
						|
	u16 csum_p;
 | 
						|
	uchar *pkt_old = pkt;
 | 
						|
 | 
						|
	len = sizeof(struct echo_msg);
 | 
						|
 | 
						|
	pkt += net_set_ether(pkt, eth_dst_addr, PROT_IP6);
 | 
						|
	pkt += ip6_add_hdr(pkt, &net_ip6, neigh_addr, PROT_ICMPV6,
 | 
						|
			   IPV6_NDISC_HOPLIMIT, len);
 | 
						|
 | 
						|
	/* ICMPv6 - Echo */
 | 
						|
	msg = (struct echo_msg *)pkt;
 | 
						|
	msg->icmph.icmp6_type = IPV6_ICMP_ECHO_REQUEST;
 | 
						|
	msg->icmph.icmp6_code = 0;
 | 
						|
	msg->icmph.icmp6_cksum = 0;
 | 
						|
	msg->icmph.icmp6_identifier = 0;
 | 
						|
	msg->icmph.icmp6_sequence = htons(seq_no++);
 | 
						|
	msg->id = msg->icmph.icmp6_identifier;	/* these seem redundant */
 | 
						|
	msg->sequence = msg->icmph.icmp6_sequence;
 | 
						|
 | 
						|
	/* checksum */
 | 
						|
	csum_p = csum_partial((u8 *)msg, len, 0);
 | 
						|
	msg->icmph.icmp6_cksum = csum_ipv6_magic(&net_ip6, neigh_addr, len,
 | 
						|
						 PROT_ICMPV6, csum_p);
 | 
						|
 | 
						|
	pkt += len;
 | 
						|
 | 
						|
	return pkt - pkt_old;
 | 
						|
}
 | 
						|
 | 
						|
int ping6_send(void)
 | 
						|
{
 | 
						|
	uchar *pkt;
 | 
						|
	static uchar mac[6];
 | 
						|
 | 
						|
	/* always send neighbor solicit */
 | 
						|
 | 
						|
	memcpy(mac, net_null_ethaddr, 6);
 | 
						|
 | 
						|
	net_nd_sol_packet_ip6 = net_ping_ip6;
 | 
						|
	net_nd_packet_mac = mac;
 | 
						|
 | 
						|
	pkt = net_nd_tx_packet;
 | 
						|
	pkt += ip6_make_ping(mac, &net_ping_ip6, pkt);
 | 
						|
 | 
						|
	/* size of the waiting packet */
 | 
						|
	net_nd_tx_packet_size = (pkt - net_nd_tx_packet);
 | 
						|
 | 
						|
	/* and do the ARP request */
 | 
						|
	net_nd_try = 1;
 | 
						|
	net_nd_timer_start = get_timer(0);
 | 
						|
	ndisc_request();
 | 
						|
	return 1;		/* waiting */
 | 
						|
}
 | 
						|
 | 
						|
static void ping6_timeout(void)
 | 
						|
{
 | 
						|
	eth_halt();
 | 
						|
	net_set_state(NETLOOP_FAIL);	/* we did not get the reply */
 | 
						|
}
 | 
						|
 | 
						|
void ping6_start(void)
 | 
						|
{
 | 
						|
	printf("Using %s device\n", eth_get_name());
 | 
						|
	net_set_timeout_handler(10000UL, ping6_timeout);
 | 
						|
 | 
						|
	ping6_send();
 | 
						|
}
 | 
						|
 | 
						|
int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
 | 
						|
{
 | 
						|
	struct icmp6hdr *icmp =
 | 
						|
	    (struct icmp6hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
 | 
						|
	struct in6_addr src_ip;
 | 
						|
 | 
						|
	switch (icmp->icmp6_type) {
 | 
						|
	case IPV6_ICMP_ECHO_REPLY:
 | 
						|
		src_ip = ip6->saddr;
 | 
						|
		if (memcmp(&net_ping_ip6, &src_ip, sizeof(struct in6_addr)))
 | 
						|
			return -EINVAL;
 | 
						|
		net_set_state(NETLOOP_SUCCESS);
 | 
						|
		break;
 | 
						|
	case IPV6_ICMP_ECHO_REQUEST:
 | 
						|
		/* ignore for now.... */
 | 
						|
		debug("Got ICMPv6 ECHO REQUEST from %pI6c\n", &ip6->saddr);
 | 
						|
		return -EINVAL;
 | 
						|
	default:
 | 
						|
		debug("Unexpected ICMPv6 type 0x%x\n", icmp->icmp6_type);
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |