+}
+#if ENABLE_PING6
+extern int BUG_bad_offsetof_icmp6_cksum(void);
+static void ping6(len_and_sockaddr *lsa)
+{
+ char packet[datalen + MAXIPLEN + MAXICMPLEN];
+ int sockopt;
+ struct msghdr msg;
+ struct sockaddr_in6 from;
+ struct iovec iov;
+ char control_buf[CMSG_SPACE(36)];
+
+ pingsock = create_icmp6_socket();
+ pingaddr.sin6 = lsa->sin6;
+ /* untested whether "-I addr" really works for IPv6: */
+ if (source_lsa)
+ xbind(pingsock, &lsa->sa, lsa->len);
+
+#ifdef ICMP6_FILTER
+ {
+ struct icmp6_filter filt;
+ if (!(option_mask32 & OPT_VERBOSE)) {
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
+ } else {
+ ICMP6_FILTER_SETPASSALL(&filt);
+ }
+ if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0)
+ bb_error_msg_and_die("setsockopt(ICMP6_FILTER)");
+ }
+#endif /*ICMP6_FILTER*/
+
+ /* enable broadcast pings */
+ setsockopt_broadcast(pingsock);
+
+ /* set recv buf for broadcast pings */
+ sockopt = 48 * 1024; /* explain why 48k? */
+ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
+
+ sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
+ if (offsetof(struct icmp6_hdr, icmp6_cksum) != 2)
+ BUG_bad_offsetof_icmp6_cksum();
+ setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
+
+ /* request ttl info to be returned in ancillary data */
+ setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, &const_int_1, sizeof(const_int_1));
+
+ if (if_index)
+ pingaddr.sin6.sin6_scope_id = if_index;
+
+ signal(SIGINT, pingstats);
+
+ /* start the ping's going ... */
+ sendping6(0);
+
+ /* listen for replies */
+ msg.msg_name = &from;
+ msg.msg_namelen = sizeof(from);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control_buf;
+ iov.iov_base = packet;
+ iov.iov_len = sizeof(packet);
+ while (1) {
+ int c;
+ struct cmsghdr *mp;
+ int hoplimit = -1;
+ msg.msg_controllen = sizeof(control_buf);
+
+ c = recvmsg(pingsock, &msg, 0);
+ if (c < 0) {
+ if (errno != EINTR)
+ bb_perror_msg("recvfrom");
+ continue;
+ }
+ for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) {
+ if (mp->cmsg_level == SOL_IPV6
+ && mp->cmsg_type == IPV6_HOPLIMIT
+ /* don't check len - we trust the kernel: */
+ /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */
+ ) {
+ hoplimit = *(int*)CMSG_DATA(mp);
+ }
+ }
+ unpack6(packet, c, &from, hoplimit);
+ if (pingcount > 0 && nreceived >= pingcount)
+ break;
+ }
+}
+#endif
+
+static void ping(len_and_sockaddr *lsa)
+{
+ printf("PING %s (%s)", hostname, dotted);
+ if (source_lsa) {
+ printf(" from %s",
+ xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len));
+ }
+ printf(": %d data bytes\n", datalen);
+
+#if ENABLE_PING6
+ if (lsa->sa.sa_family == AF_INET6)
+ ping6(lsa);
+ else
+#endif
+ ping4(lsa);