ostinato/server/winhostdevice.cpp

183 lines
5.9 KiB
C++
Raw Normal View History

/*
Copyright (C) 2018 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include "winhostdevice.h"
#include <QUuid>
2018-07-26 10:50:58 -05:00
#ifdef Q_OS_WIN32
static WCHAR errBuf[256];
static inline const char* errMsg(ulong err)
{
return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errBuf, sizeof(errBuf)-1, NULL) > 0 ?
QString("error 0x%1 %2").arg(err, 0, 16)
.arg(QString().fromWCharArray(errBuf))
.toLocal8Bit().constData() :
QString("error 0x%1").arg(err, 0, 16).toLocal8Bit().constData();
}
WindowsHostDevice::WindowsHostDevice(QString portName,
DeviceManager *deviceManager)
: Device(deviceManager)
{
GUID guid = static_cast<GUID>(QUuid(portName.right(38)));
ulong status = ConvertInterfaceGuidToLuid(&guid, &luid_);
if (status != NO_ERROR) {
qWarning("ConvertInterfaceGuidToLuid failed for %s: %s",
qPrintable(portName), errMsg(status));
luid_.Value = 0;
}
qInfo("Port %s: Luid %llx", qPrintable(portName), luid_.Value);
}
void WindowsHostDevice::receivePacket(PacketBuffer* /*pktBuf*/)
{
// Do Nothing
}
void WindowsHostDevice::clearNeighbors(Device::NeighborSet set)
{
// No need to do anything - see AbstractPort::resolveDeviceNeighbors()
// on when this is used
if (set == kUnresolvedNeighbors)
return;
NET_IFINDEX ifIndex;
ulong status = ConvertInterfaceLuidToIndex(&luid_, &ifIndex);
if (status != NO_ERROR) {
qWarning("luid2ifIdx convert failed for LUID %llx: %s",
luid_.Value, errMsg(status));
return;
}
status = FlushIpNetTable2(AF_UNSPEC, ifIndex);
if(status != NO_ERROR)
qWarning("Flush ARP/ND table failed for LUID %llx: %s",
luid_.Value, errMsg(status));
}
void WindowsHostDevice::getNeighbors(OstEmul::DeviceNeighborList *neighbors)
{
PMIB_IPNET_TABLE2 nbrs = NULL;
// TODO: optimization: use AF_UNSPEC only if hasIp4 and hasIp6
ulong status = GetIpNetTable2(AF_UNSPEC, &nbrs) != NO_ERROR;
if (status != NO_ERROR) {
qWarning("Get ARP/ND table failed for LUID %llx: %s",
luid_.Value, errMsg(status));
return;
}
for (uint i = 0; i < nbrs->NumEntries; i++) {
if (nbrs->Table[i].InterfaceLuid.Value != luid_.Value)
continue;
if (nbrs->Table[i].Address.si_family == AF_INET) {
OstEmul::ArpEntry *arp = neighbors->add_arp();
arp->set_ip4(qFromBigEndian<quint32>(
nbrs->Table[i].Address.Ipv4.sin_addr.s_addr));
arp->set_mac(qFromBigEndian<quint64>(
nbrs->Table[i].PhysicalAddress) >> 16);
}
else if (nbrs->Table[i].Address.si_family == AF_INET6) {
OstEmul::NdpEntry *ndp = neighbors->add_ndp();
ndp->mutable_ip6()->set_hi(qFromBigEndian<quint64>(
nbrs->Table[i].Address.Ipv6.sin6_addr.u.Byte));
ndp->mutable_ip6()->set_lo(qFromBigEndian<quint64>(
nbrs->Table[i].Address.Ipv6.sin6_addr.u.Byte+8));
ndp->set_mac(qFromBigEndian<quint64>(
nbrs->Table[i].PhysicalAddress) >> 16);
}
}
FreeMibTable(nbrs);
}
quint64 WindowsHostDevice::arpLookup(quint32 ip)
{
if (!luid_.Value)
return 0;
MIB_IPNET_ROW2 arpEntry;
arpEntry.InterfaceLuid = luid_;
arpEntry.Address.si_family = AF_INET;
arpEntry.Address.Ipv4.sin_addr.s_addr = qToBigEndian(ip);
if ((GetIpNetEntry2(&arpEntry) == NO_ERROR)
&& (arpEntry.PhysicalAddressLength == 6)) {
return qFromBigEndian<quint64>(arpEntry.PhysicalAddress) >> 16;
}
else
return 0;
}
quint64 WindowsHostDevice::ndpLookup(UInt128 ip)
{
if (!luid_.Value)
return 0;
MIB_IPNET_ROW2 ndpEntry;
ndpEntry.InterfaceLuid = luid_;
ndpEntry.Address.si_family = AF_INET6;
memcpy(&ndpEntry.Address.Ipv6.sin6_addr.u, ip.toArray(), 16);
if ((GetIpNetEntry2(&ndpEntry) == NO_ERROR)
&& (ndpEntry.PhysicalAddressLength == 6)) {
return qFromBigEndian<quint64>(ndpEntry.PhysicalAddress) >> 16;
}
else
return 0;
}
void WindowsHostDevice::sendArpRequest(quint32 tgtIp)
{
SOCKADDR_INET src;
src.Ipv4.sin_addr.s_addr = qToBigEndian(ip4_);
MIB_IPNET_ROW2 arpEntry;
arpEntry.InterfaceLuid = luid_;
arpEntry.Address.si_family = AF_INET;
arpEntry.Address.Ipv4.sin_addr.s_addr = qToBigEndian(tgtIp);
ulong status = ResolveIpNetEntry2(&arpEntry, &src);
if (ResolveIpNetEntry2(&arpEntry, &src) != NO_ERROR)
qWarning("Resolve arp failed for LUID %llx: %s",
luid_.Value, errMsg(status));
}
void WindowsHostDevice::sendNeighborSolicit(UInt128 tgtIp)
{
SOCKADDR_INET src;
memcpy(&src.Ipv6.sin6_addr.u, ip6_.toArray(), 16);
MIB_IPNET_ROW2 ndpEntry;
ndpEntry.InterfaceLuid = luid_;
ndpEntry.Address.si_family = AF_INET6;
memcpy(&ndpEntry.Address.Ipv6.sin6_addr.u, tgtIp.toArray(), 16);
ulong status = ResolveIpNetEntry2(&ndpEntry, &src);
if (ResolveIpNetEntry2(&ndpEntry, &src) != NO_ERROR)
qWarning("Resolve ndp failed for LUID %llx: %s",
luid_.Value, errMsg(status));
}
2018-07-26 10:50:58 -05:00
#endif