Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | // 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; } |