blob: 2479e08fd82f2d04fe48a8459608777ce4d54215 [file] [log] [blame]
Viacheslav Mitrofanove03c8aa2022-12-02 12:18:08 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2013 Allied Telesis Labs NZ
4 * Chris Packham, <judge.packham@gmail.com>
5 *
6 * Copyright (C) 2022 YADRO
7 * Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
8 */
9
10/* Simple ping6 implementation */
11
Viacheslav Mitrofanove03c8aa2022-12-02 12:18:08 +030012#include <net.h>
13#include <net6.h>
14#include "ndisc.h"
15
16static ushort seq_no;
17
18/* the ipv6 address to ping */
19struct in6_addr net_ping_ip6;
20
21int
22ip6_make_ping(uchar *eth_dst_addr, struct in6_addr *neigh_addr, uchar *pkt)
23{
24 struct echo_msg *msg;
25 u16 len;
26 u16 csum_p;
27 uchar *pkt_old = pkt;
28
29 len = sizeof(struct echo_msg);
30
31 pkt += net_set_ether(pkt, eth_dst_addr, PROT_IP6);
32 pkt += ip6_add_hdr(pkt, &net_ip6, neigh_addr, PROT_ICMPV6,
33 IPV6_NDISC_HOPLIMIT, len);
34
35 /* ICMPv6 - Echo */
36 msg = (struct echo_msg *)pkt;
37 msg->icmph.icmp6_type = IPV6_ICMP_ECHO_REQUEST;
38 msg->icmph.icmp6_code = 0;
39 msg->icmph.icmp6_cksum = 0;
40 msg->icmph.icmp6_identifier = 0;
41 msg->icmph.icmp6_sequence = htons(seq_no++);
42 msg->id = msg->icmph.icmp6_identifier; /* these seem redundant */
43 msg->sequence = msg->icmph.icmp6_sequence;
44
45 /* checksum */
46 csum_p = csum_partial((u8 *)msg, len, 0);
47 msg->icmph.icmp6_cksum = csum_ipv6_magic(&net_ip6, neigh_addr, len,
48 PROT_ICMPV6, csum_p);
49
50 pkt += len;
51
52 return pkt - pkt_old;
53}
54
55int ping6_send(void)
56{
57 uchar *pkt;
58 static uchar mac[6];
59
60 /* always send neighbor solicit */
61
62 memcpy(mac, net_null_ethaddr, 6);
63
64 net_nd_sol_packet_ip6 = net_ping_ip6;
65 net_nd_packet_mac = mac;
66
67 pkt = net_nd_tx_packet;
68 pkt += ip6_make_ping(mac, &net_ping_ip6, pkt);
69
70 /* size of the waiting packet */
71 net_nd_tx_packet_size = (pkt - net_nd_tx_packet);
72
73 /* and do the ARP request */
74 net_nd_try = 1;
75 net_nd_timer_start = get_timer(0);
76 ndisc_request();
77 return 1; /* waiting */
78}
79
80static void ping6_timeout(void)
81{
82 eth_halt();
83 net_set_state(NETLOOP_FAIL); /* we did not get the reply */
84}
85
86void ping6_start(void)
87{
88 printf("Using %s device\n", eth_get_name());
89 net_set_timeout_handler(10000UL, ping6_timeout);
90
91 ping6_send();
92}
93
94int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
95{
96 struct icmp6hdr *icmp =
97 (struct icmp6hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
98 struct in6_addr src_ip;
99
100 switch (icmp->icmp6_type) {
101 case IPV6_ICMP_ECHO_REPLY:
102 src_ip = ip6->saddr;
103 if (memcmp(&net_ping_ip6, &src_ip, sizeof(struct in6_addr)))
104 return -EINVAL;
105 net_set_state(NETLOOP_SUCCESS);
106 break;
107 case IPV6_ICMP_ECHO_REQUEST:
108 /* ignore for now.... */
109 debug("Got ICMPv6 ECHO REQUEST from %pI6c\n", &ip6->saddr);
110 return -EINVAL;
111 default:
112 debug("Unexpected ICMPv6 type 0x%x\n", icmp->icmp6_type);
113 return -EINVAL;
114 }
115
116 return 0;
117}