7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync/* $Id$ */
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync/** @file
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * NAT - Windows ICMP API based ping proxy.
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync */
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync/*
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * Copyright (C) 2006-2014 Oracle Corporation
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync *
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * available from http://www.virtualbox.org. This file is free software;
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * you can redistribute it and/or modify it under the terms of the GNU
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * General Public License (GPL) as published by the Free Software
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync */
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync#include "slirp.h"
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync#include "ip_icmp.h"
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync#include <winternl.h> /* for PIO_APC_ROUTINE &c */
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync#include <iphlpapi.h>
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync#include <icmpapi.h>
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync/*
25c6d63e535050573221f09343fd709798795443vboxsync * A header of ICMP ECHO. Intended for storage, unlike struct icmp
25c6d63e535050573221f09343fd709798795443vboxsync * which is intended to be overlayed onto a buffer.
25c6d63e535050573221f09343fd709798795443vboxsync */
25c6d63e535050573221f09343fd709798795443vboxsyncstruct icmp_echo {
25c6d63e535050573221f09343fd709798795443vboxsync uint8_t icmp_type;
25c6d63e535050573221f09343fd709798795443vboxsync uint8_t icmp_code;
25c6d63e535050573221f09343fd709798795443vboxsync uint16_t icmp_cksum;
25c6d63e535050573221f09343fd709798795443vboxsync uint16_t icmp_echo_id;
25c6d63e535050573221f09343fd709798795443vboxsync uint16_t icmp_echo_seq;
25c6d63e535050573221f09343fd709798795443vboxsync};
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsyncAssertCompileSize(struct icmp_echo, 8);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsyncstruct pong {
25c6d63e535050573221f09343fd709798795443vboxsync PNATState pData;
25c6d63e535050573221f09343fd709798795443vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_ENTRY(pong) queue_entry;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync struct ip reqiph;
25c6d63e535050573221f09343fd709798795443vboxsync struct icmp_echo reqicmph;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync size_t bufsize;
25c6d63e535050573221f09343fd709798795443vboxsync uint8_t buf[1];
25c6d63e535050573221f09343fd709798795443vboxsync};
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsyncstatic VOID WINAPI icmpwin_callback_apc(void *ctx, PIO_STATUS_BLOCK iob, ULONG reserved);
25c6d63e535050573221f09343fd709798795443vboxsyncstatic VOID WINAPI icmpwin_callback_old(void *ctx);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsyncstatic void icmpwin_callback(struct pong *pong);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsyncstatic void icmpwin_pong(struct pong *pong);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsyncstatic struct mbuf *icmpwin_get_error(struct pong *pong, int type, int code);
25c6d63e535050573221f09343fd709798795443vboxsyncstatic struct mbuf *icmpwin_get_mbuf(PNATState pData, size_t reqsize);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync/*
25c6d63e535050573221f09343fd709798795443vboxsync * On Windows XP and Windows Server 2003 IcmpSendEcho2() callback
25c6d63e535050573221f09343fd709798795443vboxsync * is FARPROC, but starting from Vista it's PIO_APC_ROUTINE with
25c6d63e535050573221f09343fd709798795443vboxsync * two extra arguments. Callbacks use WINAPI (stdcall) calling
25c6d63e535050573221f09343fd709798795443vboxsync * convention with callee responsible for popping the arguments,
25c6d63e535050573221f09343fd709798795443vboxsync * so to avoid stack corruption we check windows version at run
25c6d63e535050573221f09343fd709798795443vboxsync * time and provide correct callback.
25c6d63e535050573221f09343fd709798795443vboxsync *
25c6d63e535050573221f09343fd709798795443vboxsync * XXX: this is system-wide, but what about multiple NAT threads?
25c6d63e535050573221f09343fd709798795443vboxsync */
25c6d63e535050573221f09343fd709798795443vboxsyncstatic void *pfIcmpCallback;
25c6d63e535050573221f09343fd709798795443vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsyncint
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsyncicmpwin_init(PNATState pData)
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync{
25c6d63e535050573221f09343fd709798795443vboxsync if (pfIcmpCallback == NULL)
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync OSVERSIONINFO osvi;
25c6d63e535050573221f09343fd709798795443vboxsync int status;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
25c6d63e535050573221f09343fd709798795443vboxsync osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
25c6d63e535050573221f09343fd709798795443vboxsync status = GetVersionEx(&osvi);
25c6d63e535050573221f09343fd709798795443vboxsync if (status == 0)
25c6d63e535050573221f09343fd709798795443vboxsync return 1;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (osvi.dwMajorVersion >= 6)
25c6d63e535050573221f09343fd709798795443vboxsync pfIcmpCallback = icmpwin_callback_apc;
25c6d63e535050573221f09343fd709798795443vboxsync else
25c6d63e535050573221f09343fd709798795443vboxsync pfIcmpCallback = icmpwin_callback_old;
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_INIT(&pData->pongs_expected);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_INIT(&pData->pongs_received);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync pData->icmp_socket.sh = IcmpCreateFile();
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync pData->phEvents[VBOX_ICMP_EVENT_INDEX] = CreateEvent(NULL, FALSE, FALSE, NULL);
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync return 0;
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync}
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsyncvoid
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsyncicmpwin_finit(PNATState pData)
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync{
c9a30bece3cc55f2e139bb95fc0b5f747a7533aevboxsync IcmpCloseHandle(pData->icmp_socket.sh);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync while (!TAILQ_EMPTY(&pData->pongs_received)) {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync struct pong *pong = TAILQ_FIRST(&pData->pongs_received);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_REMOVE(&pData->pongs_received, pong, queue_entry);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync RTMemFree(pong);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync }
2b114c590cf5a19f8047cd7bde9c7e5ae00aa22bvboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync /* this should be empty */
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync while (!TAILQ_EMPTY(&pData->pongs_expected)) {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync struct pong *pong = TAILQ_FIRST(&pData->pongs_expected);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_REMOVE(&pData->pongs_expected, pong, queue_entry);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync pong->pData = NULL;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync }
7bb2e23ec5974fc83edca622a778ab403fdbf754vboxsync}
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync/*
25c6d63e535050573221f09343fd709798795443vboxsync * Outgoing ping from guest.
25c6d63e535050573221f09343fd709798795443vboxsync */
25c6d63e535050573221f09343fd709798795443vboxsyncvoid
25c6d63e535050573221f09343fd709798795443vboxsyncicmpwin_ping(PNATState pData, struct mbuf *m, int hlen)
25c6d63e535050573221f09343fd709798795443vboxsync{
25c6d63e535050573221f09343fd709798795443vboxsync struct ip *ip = mtod(m, struct ip *);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync size_t reqsize, pongsize;
25c6d63e535050573221f09343fd709798795443vboxsync uint8_t ttl;
25c6d63e535050573221f09343fd709798795443vboxsync size_t bufsize;
25c6d63e535050573221f09343fd709798795443vboxsync struct pong *pong;
25c6d63e535050573221f09343fd709798795443vboxsync IPAddr dst;
25c6d63e535050573221f09343fd709798795443vboxsync IP_OPTION_INFORMATION opts;
25c6d63e535050573221f09343fd709798795443vboxsync void *reqdata;
25c6d63e535050573221f09343fd709798795443vboxsync int status;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync ttl = ip->ip_ttl;
501dbaa85093487501f74ff32b285d2ac1f5aa0fvboxsync AssertReturnVoid(ttl > 0);
25c6d63e535050573221f09343fd709798795443vboxsync
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync reqsize = ip->ip_len - hlen - sizeof(struct icmp_echo);
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync bufsize = sizeof(ICMP_ECHO_REPLY);
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync if (reqsize < sizeof(IO_STATUS_BLOCK) + sizeof(struct icmp_echo))
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync bufsize += sizeof(IO_STATUS_BLOCK) + sizeof(struct icmp_echo);
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync else
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync bufsize += reqsize;
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync bufsize += 16; /* whatever that is; empirically at least XP needs it */
81263ca714bac5bca8e51da6658c1ad12a3a1aa2vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync pongsize = RT_OFFSETOF(struct pong, buf) + bufsize;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync if (pData->cbIcmpPending + pongsize > 1024 * 1024)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync return;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync pong = RTMemAlloc(pongsize);
25c6d63e535050573221f09343fd709798795443vboxsync if (RT_UNLIKELY(pong == NULL))
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync pong->pData = pData;
25c6d63e535050573221f09343fd709798795443vboxsync pong->bufsize = bufsize;
25c6d63e535050573221f09343fd709798795443vboxsync m_copydata(m, 0, hlen, (caddr_t)&pong->reqiph);
25c6d63e535050573221f09343fd709798795443vboxsync m_copydata(m, hlen, sizeof(struct icmp_echo), (caddr_t)&pong->reqicmph);
25c6d63e535050573221f09343fd709798795443vboxsync AssertReturnVoid(pong->reqicmph.icmp_type == ICMP_ECHO);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (m->m_next == NULL)
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync /* already in single contiguous buffer */
25c6d63e535050573221f09343fd709798795443vboxsync reqdata = mtod(m, char *) + sizeof(struct ip) + sizeof(struct icmp_echo);
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync else
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync /* use reply buffer as temporary storage */
25c6d63e535050573221f09343fd709798795443vboxsync reqdata = pong->buf;
25c6d63e535050573221f09343fd709798795443vboxsync m_copydata(m, sizeof(struct ip) + sizeof(struct icmp_echo),
25c6d63e535050573221f09343fd709798795443vboxsync reqsize, reqdata);
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync dst = ip->ip_dst.s_addr;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync opts.Ttl = ttl;
25c6d63e535050573221f09343fd709798795443vboxsync opts.Tos = ip->ip_tos; /* affected by DisableUserTOSSetting key */
25c6d63e535050573221f09343fd709798795443vboxsync opts.Flags = (ip->ip_off & IP_DF) != 0 ? IP_FLAG_DF : 0;
25c6d63e535050573221f09343fd709798795443vboxsync opts.OptionsSize = 0;
25c6d63e535050573221f09343fd709798795443vboxsync opts.OptionsData = 0;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync status = IcmpSendEcho2(pData->icmp_socket.sh, NULL,
25c6d63e535050573221f09343fd709798795443vboxsync pfIcmpCallback, pong,
25c6d63e535050573221f09343fd709798795443vboxsync dst, reqdata, (WORD)reqsize, &opts,
25c6d63e535050573221f09343fd709798795443vboxsync pong->buf, (DWORD)pong->bufsize,
25c6d63e535050573221f09343fd709798795443vboxsync 5 * 1000 /* ms */);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (RT_UNLIKELY(status != 0))
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync Log2(("NAT: IcmpSendEcho2: unexpected status %d\n", status));
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync else if ((status = GetLastError()) != ERROR_IO_PENDING)
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync int code;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync Log2(("NAT: IcmpSendEcho2: error %d\n", status));
25c6d63e535050573221f09343fd709798795443vboxsync switch (status) {
25c6d63e535050573221f09343fd709798795443vboxsync case ERROR_NETWORK_UNREACHABLE:
25c6d63e535050573221f09343fd709798795443vboxsync code = ICMP_UNREACH_NET;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync case ERROR_HOST_UNREACHABLE:
25c6d63e535050573221f09343fd709798795443vboxsync code = ICMP_UNREACH_HOST;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync default:
25c6d63e535050573221f09343fd709798795443vboxsync code = -1;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (code != -1) /* send icmp error */
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync struct mbuf *em = icmpwin_get_error(pong, ICMP_UNREACH, code);
25c6d63e535050573221f09343fd709798795443vboxsync if (em != NULL)
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync struct ip *eip = mtod(em, struct ip *);
25c6d63e535050573221f09343fd709798795443vboxsync eip->ip_src = alias_addr;
25c6d63e535050573221f09343fd709798795443vboxsync ip_output(pData, NULL, em);
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync else /* success */
25c6d63e535050573221f09343fd709798795443vboxsync {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync Log2(("NAT: pong %p for ping %RTnaipv4 id 0x%04x seq %d len %zu (%zu)\n",
25c6d63e535050573221f09343fd709798795443vboxsync pong, dst,
25c6d63e535050573221f09343fd709798795443vboxsync RT_N2H_U16(pong->reqicmph.icmp_echo_id),
25c6d63e535050573221f09343fd709798795443vboxsync RT_N2H_U16(pong->reqicmph.icmp_echo_seq),
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync pongsize, reqsize));
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync pData->cbIcmpPending += pongsize;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_INSERT_TAIL(&pData->pongs_expected, pong, queue_entry);
25c6d63e535050573221f09343fd709798795443vboxsync pong = NULL; /* callback owns it now */
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (pong != NULL)
25c6d63e535050573221f09343fd709798795443vboxsync RTMemFree(pong);
25c6d63e535050573221f09343fd709798795443vboxsync}
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsyncstatic VOID WINAPI
25c6d63e535050573221f09343fd709798795443vboxsyncicmpwin_callback_apc(void *ctx, PIO_STATUS_BLOCK iob, ULONG reserved)
25c6d63e535050573221f09343fd709798795443vboxsync{
25c6d63e535050573221f09343fd709798795443vboxsync struct pong *pong = (struct pong *)ctx;
25c6d63e535050573221f09343fd709798795443vboxsync if (pong != NULL)
25c6d63e535050573221f09343fd709798795443vboxsync icmpwin_callback(pong);
25c6d63e535050573221f09343fd709798795443vboxsync}
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsyncstatic VOID WINAPI
25c6d63e535050573221f09343fd709798795443vboxsyncicmpwin_callback_old(void *ctx)
25c6d63e535050573221f09343fd709798795443vboxsync{
25c6d63e535050573221f09343fd709798795443vboxsync struct pong *pong = (struct pong *)ctx;
25c6d63e535050573221f09343fd709798795443vboxsync if (pong != NULL)
25c6d63e535050573221f09343fd709798795443vboxsync icmpwin_callback(pong);
25c6d63e535050573221f09343fd709798795443vboxsync}
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync/*
25c6d63e535050573221f09343fd709798795443vboxsync * Actual callback code for IcmpSendEcho2(). OS version specific
25c6d63e535050573221f09343fd709798795443vboxsync * trampoline will free "pong" argument for us.
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync *
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync * Since async callback can be called anytime the thread is alertable,
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync * it's not safe to do any processing here. Instead queue it and
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync * notify the main loop.
25c6d63e535050573221f09343fd709798795443vboxsync */
25c6d63e535050573221f09343fd709798795443vboxsyncstatic void
25c6d63e535050573221f09343fd709798795443vboxsyncicmpwin_callback(struct pong *pong)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync{
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync PNATState pData = pong->pData;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync if (pData == NULL)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync RTMemFree(pong);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync return;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync }
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync#ifdef DEBUG
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync struct pong *expected, *already;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_FOREACH(expected, &pData->pongs_expected, queue_entry)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync if (expected == pong)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync break;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync }
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync Assert(expected);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_FOREACH(already, &pData->pongs_received, queue_entry)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync if (already == pong)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync break;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync }
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync Assert(!already);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync }
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync#endif
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_REMOVE(&pData->pongs_expected, pong, queue_entry);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_INSERT_TAIL(&pData->pongs_received, pong, queue_entry);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync WSASetEvent(pData->phEvents[VBOX_ICMP_EVENT_INDEX]);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync}
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsyncvoid
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsyncicmpwin_process(PNATState pData)
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync{
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync struct pong_tailq pongs;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync if (TAILQ_EMPTY(&pData->pongs_received))
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync return;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_INIT(&pongs);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_CONCAT(&pongs, &pData->pongs_received, queue_entry);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync while (!TAILQ_EMPTY(&pongs)) {
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync struct pong *pong = TAILQ_FIRST(&pongs);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync size_t sz;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync sz = RT_OFFSETOF(struct pong, buf) + pong->bufsize;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync Assert(pData->cbIcmpPending >= sz);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync pData->cbIcmpPending -= sz;
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync icmpwin_pong(pong);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync TAILQ_REMOVE(&pongs, pong, queue_entry);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync RTMemFree(pong);
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync }
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync}
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsync
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsyncvoid
cd0a67b2dd5f66f87aca9ad79dda62a2ce142817vboxsyncicmpwin_pong(struct pong *pong)
25c6d63e535050573221f09343fd709798795443vboxsync{
25c6d63e535050573221f09343fd709798795443vboxsync PNATState pData;
25c6d63e535050573221f09343fd709798795443vboxsync DWORD nreplies;
25c6d63e535050573221f09343fd709798795443vboxsync ICMP_ECHO_REPLY *reply;
25c6d63e535050573221f09343fd709798795443vboxsync struct mbuf *m;
25c6d63e535050573221f09343fd709798795443vboxsync struct ip *ip;
25c6d63e535050573221f09343fd709798795443vboxsync struct icmp_echo *icmp;
25c6d63e535050573221f09343fd709798795443vboxsync size_t reqsize;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync pData = pong->pData; /* to make slirp_state.h macro hackery work */
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync nreplies = IcmpParseReplies(pong->buf, (DWORD)pong->bufsize);
25c6d63e535050573221f09343fd709798795443vboxsync if (nreplies == 0)
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync DWORD error = GetLastError();
25c6d63e535050573221f09343fd709798795443vboxsync if (error == IP_REQ_TIMED_OUT)
25c6d63e535050573221f09343fd709798795443vboxsync Log2(("NAT: ping %p timed out\n", (void *)pong));
25c6d63e535050573221f09343fd709798795443vboxsync else
25c6d63e535050573221f09343fd709798795443vboxsync Log2(("NAT: ping %p: IcmpParseReplies: error %d\n",
25c6d63e535050573221f09343fd709798795443vboxsync (void *)pong, error));
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync reply = (ICMP_ECHO_REPLY *)pong->buf;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (reply->Status == IP_SUCCESS)
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync if (reply->Options.OptionsSize != 0) /* don't do options */
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync /* need to remap &reply->Address ? */
25c6d63e535050573221f09343fd709798795443vboxsync if (/* not a mapped loopback */ 1)
25c6d63e535050573221f09343fd709798795443vboxsync {
25c6d63e535050573221f09343fd709798795443vboxsync if (reply->Options.Ttl <= 1)
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync --reply->Options.Ttl;
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync reqsize = reply->DataSize;
25c6d63e535050573221f09343fd709798795443vboxsync if ( (reply->Options.Flags & IP_FLAG_DF) != 0
25c6d63e535050573221f09343fd709798795443vboxsync && sizeof(struct ip) + sizeof(struct icmp_echo) + reqsize > if_mtu)
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync m = icmpwin_get_mbuf(pData, reqsize);
25c6d63e535050573221f09343fd709798795443vboxsync if (m == NULL)
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync ip = mtod(m, struct ip *);
25c6d63e535050573221f09343fd709798795443vboxsync icmp = (struct icmp_echo *)(mtod(m, char *) + sizeof(*ip));
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync /* fill in ip (ip_output0() does the boilerplate for us) */
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_tos = reply->Options.Tos;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_len = sizeof(*ip) + sizeof(*icmp) + reqsize;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_off = 0;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_ttl = reply->Options.Ttl;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_p = IPPROTO_ICMP;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_src.s_addr = reply->Address;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_dst = pong->reqiph.ip_src;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_type = ICMP_ECHOREPLY;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_code = 0;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_cksum = 0;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_echo_id = pong->reqicmph.icmp_echo_id;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_echo_seq = pong->reqicmph.icmp_echo_seq;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync m_append(pData, m, reqsize, reply->Data);
25c6d63e535050573221f09343fd709798795443vboxsync
5f83ab060c98132ab115599b8f2fb5fbc819ed1dvboxsync icmp->icmp_cksum = in_cksum_skip(m, ip->ip_len, sizeof(*ip));
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync else {
25c6d63e535050573221f09343fd709798795443vboxsync uint8_t type, code;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync switch (reply->Status) {
25c6d63e535050573221f09343fd709798795443vboxsync case IP_DEST_NET_UNREACHABLE:
25c6d63e535050573221f09343fd709798795443vboxsync type = ICMP_UNREACH; code = ICMP_UNREACH_NET;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync case IP_DEST_HOST_UNREACHABLE:
25c6d63e535050573221f09343fd709798795443vboxsync type = ICMP_UNREACH; code = ICMP_UNREACH_HOST;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync case IP_DEST_PROT_UNREACHABLE:
25c6d63e535050573221f09343fd709798795443vboxsync type = ICMP_UNREACH; code = ICMP_UNREACH_PROTOCOL;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync case IP_PACKET_TOO_BIG:
25c6d63e535050573221f09343fd709798795443vboxsync type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync case IP_SOURCE_QUENCH:
25c6d63e535050573221f09343fd709798795443vboxsync type = ICMP_SOURCEQUENCH; code = 0;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync case IP_TTL_EXPIRED_TRANSIT:
25c6d63e535050573221f09343fd709798795443vboxsync type = ICMP_TIMXCEED; code = ICMP_TIMXCEED_INTRANS;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync case IP_TTL_EXPIRED_REASSEM:
25c6d63e535050573221f09343fd709798795443vboxsync type = ICMP_TIMXCEED; code = ICMP_TIMXCEED_REASS;
25c6d63e535050573221f09343fd709798795443vboxsync break;
25c6d63e535050573221f09343fd709798795443vboxsync default:
25c6d63e535050573221f09343fd709798795443vboxsync Log2(("NAT: ping reply status %d, dropped\n", reply->Status));
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync Log2(("NAT: ping status %d -> type %d/code %d\n",
25c6d63e535050573221f09343fd709798795443vboxsync reply->Status, type, code));
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync /*
25c6d63e535050573221f09343fd709798795443vboxsync * XXX: we don't know the TTL of the request at the time this
25c6d63e535050573221f09343fd709798795443vboxsync * ICMP error was generated (we can guess it was 1 for ttl
25c6d63e535050573221f09343fd709798795443vboxsync * exceeded, but don't bother faking it).
25c6d63e535050573221f09343fd709798795443vboxsync */
25c6d63e535050573221f09343fd709798795443vboxsync m = icmpwin_get_error(pong, type, code);
25c6d63e535050573221f09343fd709798795443vboxsync if (m == NULL)
25c6d63e535050573221f09343fd709798795443vboxsync return;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync ip = mtod(m, struct ip *);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_tos = reply->Options.Tos;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_ttl = reply->Options.Ttl; /* XXX: decrement */
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_src.s_addr = reply->Address;
25c6d63e535050573221f09343fd709798795443vboxsync }
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync Assert(ip->ip_len == m_length(m, NULL));
25c6d63e535050573221f09343fd709798795443vboxsync ip_output(pData, NULL, m);
25c6d63e535050573221f09343fd709798795443vboxsync}
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync/*
25c6d63e535050573221f09343fd709798795443vboxsync * Prepare mbuf with ICMP error type/code.
25c6d63e535050573221f09343fd709798795443vboxsync * IP source must be filled by the caller.
25c6d63e535050573221f09343fd709798795443vboxsync */
25c6d63e535050573221f09343fd709798795443vboxsyncstatic struct mbuf *
25c6d63e535050573221f09343fd709798795443vboxsyncicmpwin_get_error(struct pong *pong, int type, int code)
25c6d63e535050573221f09343fd709798795443vboxsync{
25c6d63e535050573221f09343fd709798795443vboxsync PNATState pData = pong->pData;
25c6d63e535050573221f09343fd709798795443vboxsync struct mbuf *m;
25c6d63e535050573221f09343fd709798795443vboxsync struct ip *ip;
25c6d63e535050573221f09343fd709798795443vboxsync struct icmp_echo *icmp;
25c6d63e535050573221f09343fd709798795443vboxsync size_t reqsize;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync Log2(("NAT: ping error type %d/code %d\n", type, code));
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync reqsize = sizeof(pong->reqiph) + sizeof(pong->reqicmph);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync m = icmpwin_get_mbuf(pData, reqsize);
25c6d63e535050573221f09343fd709798795443vboxsync if (m == NULL)
25c6d63e535050573221f09343fd709798795443vboxsync return NULL;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync ip = mtod(m, struct ip *);
25c6d63e535050573221f09343fd709798795443vboxsync icmp = (struct icmp_echo *)(mtod(m, char *) + sizeof(*ip));
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_tos = 0;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_len = sizeof(*ip) + sizeof(*icmp) + reqsize;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_off = 0;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_ttl = IPDEFTTL;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_p = IPPROTO_ICMP;
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_src.s_addr = 0; /* NB */
25c6d63e535050573221f09343fd709798795443vboxsync ip->ip_dst = pong->reqiph.ip_src;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_type = type;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_code = code;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_cksum = 0;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_echo_id = 0;
25c6d63e535050573221f09343fd709798795443vboxsync icmp->icmp_echo_seq = 0;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync m_append(pData, m, sizeof(pong->reqiph), (caddr_t)&pong->reqiph);
25c6d63e535050573221f09343fd709798795443vboxsync m_append(pData, m, sizeof(pong->reqicmph), (caddr_t)&pong->reqicmph);
25c6d63e535050573221f09343fd709798795443vboxsync
5f83ab060c98132ab115599b8f2fb5fbc819ed1dvboxsync icmp->icmp_cksum = in_cksum_skip(m, ip->ip_len, sizeof(*ip));
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync return m;
25c6d63e535050573221f09343fd709798795443vboxsync}
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync/*
25c6d63e535050573221f09343fd709798795443vboxsync * Replacing original simple slirp mbufs with real mbufs from freebsd
25c6d63e535050573221f09343fd709798795443vboxsync * was a bit messy since assumption are different. This leads to
25c6d63e535050573221f09343fd709798795443vboxsync * rather ugly code at times. Hide the gore here.
25c6d63e535050573221f09343fd709798795443vboxsync */
25c6d63e535050573221f09343fd709798795443vboxsyncstatic struct mbuf *
25c6d63e535050573221f09343fd709798795443vboxsyncicmpwin_get_mbuf(PNATState pData, size_t reqsize)
25c6d63e535050573221f09343fd709798795443vboxsync{
25c6d63e535050573221f09343fd709798795443vboxsync struct mbuf *m;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync reqsize += if_maxlinkhdr;
25c6d63e535050573221f09343fd709798795443vboxsync reqsize += sizeof(struct ip) + sizeof(struct icmp_echo);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (reqsize <= MHLEN)
25c6d63e535050573221f09343fd709798795443vboxsync /* good pings come in small packets */
25c6d63e535050573221f09343fd709798795443vboxsync m = m_gethdr(pData, M_NOWAIT, MT_HEADER);
25c6d63e535050573221f09343fd709798795443vboxsync else
25c6d63e535050573221f09343fd709798795443vboxsync m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, slirp_size(pData));
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync if (m == NULL)
25c6d63e535050573221f09343fd709798795443vboxsync return NULL;
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync m->m_flags |= M_SKIP_FIREWALL;
25c6d63e535050573221f09343fd709798795443vboxsync m->m_data += if_maxlinkhdr; /* reserve leading space for ethernet header */
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync m->m_pkthdr.header = mtod(m, void *);
25c6d63e535050573221f09343fd709798795443vboxsync m->m_len = sizeof(struct ip) + sizeof(struct icmp_echo);
25c6d63e535050573221f09343fd709798795443vboxsync
25c6d63e535050573221f09343fd709798795443vboxsync return m;
25c6d63e535050573221f09343fd709798795443vboxsync}