mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-23 00:30:17 +00:00
163 lines
5.2 KiB
C++
163 lines
5.2 KiB
C++
|
/*
|
||
|
AppleWin : An Apple //e emulator for Windows
|
||
|
|
||
|
Copyright (C) 2022, Andrea Odetti
|
||
|
|
||
|
AppleWin 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 2 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
AppleWin 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 AppleWin; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*/
|
||
|
|
||
|
#include "StdAfx.h"
|
||
|
|
||
|
#include "IPRaw.h"
|
||
|
|
||
|
#ifndef _MSC_VER
|
||
|
#include <arpa/inet.h>
|
||
|
#endif
|
||
|
|
||
|
#define IPV4 0x04
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
|
||
|
#pragma pack(push)
|
||
|
#pragma pack(1) // Ensure struct is packed
|
||
|
struct IP4Header
|
||
|
{
|
||
|
uint8_t ihl : 4;
|
||
|
uint8_t version : 4;
|
||
|
uint8_t tos;
|
||
|
uint16_t len;
|
||
|
uint16_t id;
|
||
|
uint16_t flags : 3;
|
||
|
uint16_t fragmentOffset : 13;
|
||
|
uint8_t ttl;
|
||
|
uint8_t proto;
|
||
|
uint16_t checksum;
|
||
|
uint32_t sourceAddress;
|
||
|
uint32_t destinationAddress;
|
||
|
};
|
||
|
|
||
|
struct ETH2Frame
|
||
|
{
|
||
|
uint8_t destinationMac[6];
|
||
|
uint8_t sourceMac[6];
|
||
|
uint16_t type;
|
||
|
};
|
||
|
#pragma pack(pop)
|
||
|
|
||
|
uint32_t sum_every_16bits(const void *addr, int count)
|
||
|
{
|
||
|
uint32_t sum = 0;
|
||
|
const uint16_t *ptr = reinterpret_cast<const uint16_t *>(addr);
|
||
|
|
||
|
while (count > 1)
|
||
|
{
|
||
|
/* This is the inner loop */
|
||
|
sum += *ptr++;
|
||
|
count -= 2;
|
||
|
}
|
||
|
|
||
|
/* Add left-over byte, if any */
|
||
|
if (count > 0)
|
||
|
sum += *reinterpret_cast<const uint8_t *>(ptr);
|
||
|
|
||
|
return sum;
|
||
|
}
|
||
|
|
||
|
uint16_t checksum(const void *addr, int count)
|
||
|
{
|
||
|
/* Compute Internet Checksum for "count" bytes
|
||
|
* beginning at location "addr".
|
||
|
* Taken from https://tools.ietf.org/html/rfc1071
|
||
|
*/
|
||
|
uint32_t sum = sum_every_16bits(addr, count);
|
||
|
|
||
|
/* Fold 32-bit sum to 16 bits */
|
||
|
while (sum >> 16)
|
||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||
|
|
||
|
return ~sum;
|
||
|
}
|
||
|
|
||
|
// get the minimum size of a ETH Frame that contains a IP payload
|
||
|
// 34 = 14 bytes for ETH2 + 20 bytes IPv4 (minimum)
|
||
|
int getIPMinimumSize()
|
||
|
{
|
||
|
const int minimumSize = sizeof(ETH2Frame) + sizeof(IP4Header) + 0; // 0 len
|
||
|
return minimumSize;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
std::vector<uint8_t> createETH2Frame(const std::vector<uint8_t> &data,
|
||
|
const MACAddress *sourceMac, const MACAddress *destinationMac,
|
||
|
const uint8_t ttl, const uint8_t tos, const uint8_t protocol,
|
||
|
const uint32_t sourceAddress, const uint32_t destinationAddress)
|
||
|
{
|
||
|
const size_t total = sizeof(ETH2Frame) + sizeof(IP4Header) + data.size();
|
||
|
std::vector<uint8_t> frame(total);
|
||
|
ETH2Frame *eth2frame = reinterpret_cast<ETH2Frame *>(frame.data() + 0);
|
||
|
memcpy(eth2frame->destinationMac, destinationMac, sizeof(eth2frame->destinationMac));
|
||
|
memcpy(eth2frame->sourceMac, sourceMac, sizeof(eth2frame->destinationMac));
|
||
|
eth2frame->type = htons(0x0800);
|
||
|
IP4Header *ip4header = reinterpret_cast<IP4Header *>(frame.data() + sizeof(ETH2Frame));
|
||
|
|
||
|
ip4header->version = IPV4;
|
||
|
ip4header->ihl = 0x05; // minimum size = 20 bytes, without any extra option
|
||
|
ip4header->tos = tos;
|
||
|
ip4header->len = htons(static_cast<uint16_t>(sizeof(IP4Header) + data.size()));
|
||
|
ip4header->id = 0;
|
||
|
ip4header->fragmentOffset = 0;
|
||
|
ip4header->ttl = ttl;
|
||
|
ip4header->proto = protocol;
|
||
|
ip4header->sourceAddress = sourceAddress;
|
||
|
ip4header->destinationAddress = destinationAddress;
|
||
|
ip4header->checksum = checksum(ip4header, sizeof(IP4Header));
|
||
|
|
||
|
memcpy(frame.data() + sizeof(ETH2Frame) + sizeof(IP4Header), data.data(), data.size());
|
||
|
|
||
|
return frame;
|
||
|
}
|
||
|
|
||
|
void getIPPayload(const int lengthOfFrame, const uint8_t *frame,
|
||
|
size_t &lengthOfPayload, const uint8_t *&payload, uint32_t &destination, uint8_t &protocol)
|
||
|
{
|
||
|
const int minimumSize = getIPMinimumSize();
|
||
|
if (lengthOfFrame > minimumSize)
|
||
|
{
|
||
|
const ETH2Frame *eth2Frame = reinterpret_cast<const ETH2Frame *>(frame);
|
||
|
const IP4Header *ip4header = reinterpret_cast<const IP4Header *>(frame + sizeof(ETH2Frame));
|
||
|
if (eth2Frame->type == htons(0x0800) && ip4header->version == IPV4)
|
||
|
{
|
||
|
const uint16_t ipv4HeaderSize = ip4header->ihl * 4;
|
||
|
const uint16_t ipPacketSize = ntohs(ip4header->len);
|
||
|
const int expectedSize = sizeof(ETH2Frame) + ipPacketSize;
|
||
|
if (ipPacketSize > ipv4HeaderSize && lengthOfFrame >= expectedSize)
|
||
|
{
|
||
|
protocol = ip4header->proto;
|
||
|
payload = frame + sizeof(ETH2Frame) + ipv4HeaderSize;
|
||
|
lengthOfPayload = ipPacketSize - ipv4HeaderSize;
|
||
|
destination = ip4header->destinationAddress;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// not a good packet
|
||
|
protocol = 0xFF; // reserved protocol
|
||
|
payload = nullptr;
|
||
|
lengthOfPayload = 0;
|
||
|
destination = 0;
|
||
|
}
|