xaizek / tos (License: GPLv3 only) (since 2018-12-07)
This is an alternative version of sources presented as part of Write Your Own OS video tutorial by Viktor Engelmann.
<root> / src / net / etherframe.cpp (418709f73a1bd32f3ba6974f5329a15a51d12863) (2,363B) (mode 100644) [raw]
#include "net/etherframe.hpp"

#include "utils/conv.hpp"

#include <memory>

using namespace net;

EtherFrameHandler::EtherFrameHandler(EtherFrameProvider &backend,
                                     std::uint16_t etherType)
    : backend(backend), etherType(hton(etherType))
{
    backend.handlers[this->etherType.BE] = this;
}

EtherFrameHandler::~EtherFrameHandler()
{
    if (backend.handlers[etherType.BE] == this) {
        backend.handlers[etherType.BE] = nullptr;
    }
}

void
EtherFrameHandler::send(NetOrder<std::uint64_t> dstMAC,
                        span<const std::uint8_t> msg)
{
    return backend.send(dstMAC, etherType, msg);
}


NetOrder<std::uint32_t>
EtherFrameHandler::getIPAddress() const
{
    return backend.getIPAddress();
}

EtherFrameProvider::EtherFrameProvider(drv::EthernetDriver &backend)
    : RawDataHandler(backend)
{
    for (std::uint32_t i = 0; i < 65535; ++i) {
        handlers[i] = 0;
    }
}

bool
EtherFrameProvider::onRawDataReceived(span<std::uint8_t> msg)
{
    if (msg.size() < EtherFrameHeader::size()) {
        return false;
    }

    EtherFrameHeader frame(msg.data());
    bool sendBack = false;

    if (frame.dstMAC == broadcastMAC || frame.dstMAC == backend.getMAC()) {
        if (EtherFrameHandler *handler = handlers[frame.etherType.BE]) {
            sendBack = handler->onEtherFrameReceived(msg.after(frame.size()));
        }
    }

    if (sendBack) {
        frame.dstMAC = frame.srcMAC;
        frame.srcMAC = backend.getMAC();
    }

    return sendBack;
}

void
EtherFrameProvider::send(NetOrder<std::uint64_t> dstMAC,
                         NetOrder<std::uint16_t> etherType,
                         span<const std::uint8_t> msg)
{
    std::unique_ptr<std::uint8_t[]> buffer {
        new std::uint8_t[EtherFrameHeader::size() + msg.size()]
    };

    EtherFrameHeader frame(buffer.get());
    frame.dstMAC = dstMAC;
    frame.srcMAC = backend.getMAC();
    frame.etherType = etherType;

    std::uint8_t *dst = buffer.get() + frame.size();
    for (int i = 0; i < msg.size(); ++i) {
        dst[i] = msg[i];
    }

    backend.send({ buffer.get(), msg.size() + frame.size() });
}

NetOrder<std::uint64_t>
EtherFrameProvider::getMACAddress() const
{
    return backend.getMAC();
}

NetOrder<std::uint32_t>
EtherFrameProvider::getIPAddress() const
{
    return backend.getIPAddress();
}
Hints

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