]>
Commit | Line | Data |
---|---|---|
eeb0a2c6 VM |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2013 Allied Telesis Labs NZ | |
4 | * Chris Packham, <[email protected]> | |
5 | * | |
6 | * Copyright (C) 2022 YADRO | |
7 | * Viacheslav Mitrofanov <[email protected]> | |
8 | */ | |
9 | ||
10 | /* Simple ping6 implementation */ | |
11 | ||
eeb0a2c6 VM |
12 | #include <net.h> |
13 | #include <net6.h> | |
14 | #include "ndisc.h" | |
15 | ||
16 | static ushort seq_no; | |
17 | ||
18 | /* the ipv6 address to ping */ | |
19 | struct in6_addr net_ping_ip6; | |
20 | ||
21 | int | |
22 | ip6_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 | ||
55 | int 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 | ||
80 | static void ping6_timeout(void) | |
81 | { | |
82 | eth_halt(); | |
83 | net_set_state(NETLOOP_FAIL); /* we did not get the reply */ | |
84 | } | |
85 | ||
86 | void 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 | ||
94 | int 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 | } |