#include "net/arp.hpp"
#include "utils/conv.hpp"
using namespace net;
constexpr auto ethernetType = toNetOrder<std::uint16_t>(0x0001);
constexpr auto ip4Protocol = toNetOrder<std::uint16_t>(0x0800);
constexpr auto requestCmd = toNetOrder<std::uint16_t>(0x0001);
constexpr auto responseCmd = toNetOrder<std::uint16_t>(0x0002);
ARP::ARP(EtherFrameProvider &backend)
: EtherFrameHandler(backend, 0x0806), numCacheEntries(0)
{
}
bool
ARP::onEtherFrameReceived(span<std::uint8_t> msg)
{
if (msg.size() < ARPMsg::size()) {
return false;
}
ARPMsg arp(msg.data());
if (arp.hardwareType == ethernetType &&
arp.protocol == ip4Protocol &&
arp.hardwareAddressSize.BE == 6 &&
arp.protocolAddressSize.BE == 4 &&
arp.dstIP == backend.getIPAddress()) {
switch (arp.command.BE) {
case requestCmd.BE:
arp.command = responseCmd;
arp.dstIP = arp.srcIP;
arp.dstMAC = arp.srcMAC;
arp.srcIP = backend.getIPAddress();
arp.srcMAC = backend.getMACAddress();
return true;
case responseCmd.BE:
if (numCacheEntries < maxCacheEntries) {
IPcache[numCacheEntries] = arp.srcIP;
MACcache[numCacheEntries] = arp.srcMAC;
++numCacheEntries;
}
break;
}
}
return false;
}
void
ARP::requestMACAddress(NetOrder<std::uint32_t> ip)
{
std::uint8_t data[ARPMsg::size()];
ARPMsg arp(data);
arp.hardwareType = ethernetType;
arp.protocol = ip4Protocol;
arp.hardwareAddressSize = NetOrder<std::uint8_t>(6); // mac
arp.protocolAddressSize = NetOrder<std::uint8_t>(4); // ipv4
arp.command = requestCmd;
arp.srcMAC = backend.getMACAddress();
arp.srcIP = backend.getIPAddress();
arp.dstMAC = broadcastMAC;
arp.dstIP = ip;
send(arp.dstMAC, data);
}
void
ARP::broadcastMACAddress(NetOrder<std::uint32_t> ip)
{
std::uint8_t data[ARPMsg::size()];
ARPMsg arp(data);
arp.hardwareType = ethernetType;
arp.protocol = ip4Protocol;
arp.hardwareAddressSize = NetOrder<std::uint8_t>(6); // mac
arp.protocolAddressSize = NetOrder<std::uint8_t>(4); // ipv4
arp.command = responseCmd;
arp.srcMAC = backend.getMACAddress();
arp.srcIP = backend.getIPAddress();
arp.dstMAC = resolve(ip);
arp.dstIP = ip;
send(arp.dstMAC, data);
}
NetOrder<std::uint64_t>
ARP::getMACFromCache(NetOrder<std::uint32_t> ip)
{
for (int i = 0; i < numCacheEntries; ++i) {
if (IPcache[i] == ip) {
return MACcache[i];
}
}
return broadcastMAC;
}
NetOrder<std::uint64_t>
ARP::resolve(NetOrder<std::uint32_t> ip)
{
NetOrder<std::uint64_t> result = getMACFromCache(ip);
if (result == broadcastMAC) {
requestMACAddress(ip);
}
// Possibly infinite loop.
while (result == broadcastMAC) {
result = getMACFromCache(ip);
}
return result;
}
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"
Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos
Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos
You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a
pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master