1258945Sroberto// SPDX-License-Identifier: GPL-2.0+ 2258945Sroberto/* 3258945Sroberto * Copyright (C) 2013 Allied Telesis Labs NZ 4258945Sroberto * Chris Packham, <judge.packham@gmail.com> 5258945Sroberto * 6258945Sroberto * Copyright (C) 2022 YADRO 7258945Sroberto * Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com> 8258945Sroberto */ 9258945Sroberto 10258945Sroberto/* Simple ping6 implementation */ 11258945Sroberto 12258945Sroberto#include <common.h> 13258945Sroberto#include <net.h> 14258945Sroberto#include <net6.h> 15258945Sroberto#include "ndisc.h" 16258945Sroberto 17258945Srobertostatic ushort seq_no; 18258945Sroberto 19258945Sroberto/* the ipv6 address to ping */ 20258945Srobertostruct in6_addr net_ping_ip6; 21258945Sroberto 22258945Srobertoint 23258945Srobertoip6_make_ping(uchar *eth_dst_addr, struct in6_addr *neigh_addr, uchar *pkt) 24258945Sroberto{ 25258945Sroberto struct echo_msg *msg; 26258945Sroberto u16 len; 27258945Sroberto u16 csum_p; 28258945Sroberto uchar *pkt_old = pkt; 29258945Sroberto 30258945Sroberto len = sizeof(struct echo_msg); 31258945Sroberto 32258945Sroberto pkt += net_set_ether(pkt, eth_dst_addr, PROT_IP6); 33258945Sroberto pkt += ip6_add_hdr(pkt, &net_ip6, neigh_addr, PROT_ICMPV6, 34258945Sroberto IPV6_NDISC_HOPLIMIT, len); 35258945Sroberto 36258945Sroberto /* ICMPv6 - Echo */ 37258945Sroberto msg = (struct echo_msg *)pkt; 38258945Sroberto msg->icmph.icmp6_type = IPV6_ICMP_ECHO_REQUEST; 39258945Sroberto msg->icmph.icmp6_code = 0; 40258945Sroberto msg->icmph.icmp6_cksum = 0; 41258945Sroberto msg->icmph.icmp6_identifier = 0; 42258945Sroberto msg->icmph.icmp6_sequence = htons(seq_no++); 43258945Sroberto msg->id = msg->icmph.icmp6_identifier; /* these seem redundant */ 44258945Sroberto msg->sequence = msg->icmph.icmp6_sequence; 45258945Sroberto 46258945Sroberto /* checksum */ 47258945Sroberto csum_p = csum_partial((u8 *)msg, len, 0); 48258945Sroberto msg->icmph.icmp6_cksum = csum_ipv6_magic(&net_ip6, neigh_addr, len, 49258945Sroberto PROT_ICMPV6, csum_p); 50258945Sroberto 51258945Sroberto pkt += len; 52258945Sroberto 53258945Sroberto return pkt - pkt_old; 54258945Sroberto} 55258945Sroberto 56258945Srobertoint ping6_send(void) 57258945Sroberto{ 58258945Sroberto uchar *pkt; 59258945Sroberto static uchar mac[6]; 60258945Sroberto 61258945Sroberto /* always send neighbor solicit */ 62258945Sroberto 63258945Sroberto memcpy(mac, net_null_ethaddr, 6); 64258945Sroberto 65258945Sroberto net_nd_sol_packet_ip6 = net_ping_ip6; 66258945Sroberto net_nd_packet_mac = mac; 67258945Sroberto 68258945Sroberto pkt = net_nd_tx_packet; 69258945Sroberto pkt += ip6_make_ping(mac, &net_ping_ip6, pkt); 70258945Sroberto 71258945Sroberto /* size of the waiting packet */ 72258945Sroberto net_nd_tx_packet_size = (pkt - net_nd_tx_packet); 73258945Sroberto 74258945Sroberto /* and do the ARP request */ 75258945Sroberto net_nd_try = 1; 76258945Sroberto net_nd_timer_start = get_timer(0); 77258945Sroberto ndisc_request(); 78258945Sroberto return 1; /* waiting */ 79258945Sroberto} 80258945Sroberto 81258945Srobertostatic void ping6_timeout(void) 82258945Sroberto{ 83258945Sroberto eth_halt(); 84258945Sroberto net_set_state(NETLOOP_FAIL); /* we did not get the reply */ 85258945Sroberto} 86258945Sroberto 87258945Srobertovoid ping6_start(void) 88258945Sroberto{ 89258945Sroberto printf("Using %s device\n", eth_get_name()); 90258945Sroberto net_set_timeout_handler(10000UL, ping6_timeout); 91258945Sroberto 92258945Sroberto ping6_send(); 93258945Sroberto} 94258945Sroberto 95258945Srobertoint ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len) 96258945Sroberto{ 97258945Sroberto struct icmp6hdr *icmp = 98258945Sroberto (struct icmp6hdr *)(((uchar *)ip6) + IP6_HDR_SIZE); 99258945Sroberto struct in6_addr src_ip; 100258945Sroberto 101258945Sroberto switch (icmp->icmp6_type) { 102258945Sroberto case IPV6_ICMP_ECHO_REPLY: 103258945Sroberto src_ip = ip6->saddr; 104258945Sroberto if (memcmp(&net_ping_ip6, &src_ip, sizeof(struct in6_addr))) 105258945Sroberto return -EINVAL; 106258945Sroberto net_set_state(NETLOOP_SUCCESS); 107258945Sroberto break; 108258945Sroberto case IPV6_ICMP_ECHO_REQUEST: 109258945Sroberto /* ignore for now.... */ 110258945Sroberto debug("Got ICMPv6 ECHO REQUEST from %pI6c\n", &ip6->saddr); 111258945Sroberto return -EINVAL; 112258945Sroberto default: 113258945Sroberto debug("Unexpected ICMPv6 type 0x%x\n", icmp->icmp6_type); 114258945Sroberto return -EINVAL; 115258945Sroberto } 116258945Sroberto 117258945Sroberto return 0; 118258945Sroberto} 119258945Sroberto