A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

eth/eth.cpp

Committer:
andrewboyson
Date:
2017-05-01
Revision:
13:9cd54f7db57a
Parent:
11:c051adb70c5a
Child:
14:e75a59c1123d

File content as of revision 13:9cd54f7db57a:

#include "mbed.h"
#include   "io.h"
#include  "log.h"
#include  "net.h"
#include  "arp.h"
#include  "ip4.h"
#include  "ip6.h"
#include  "phy.h"
#include  "eth.h"
#include  "mac.h"

#define HEADER_SIZE 14

#define DEBUG false

__packed struct header
{
    char     dst[6];
    char     src[6];
    uint16_t typ;
};

static void typeToString(uint16_t type, int size, char* text)
{
    switch (type)
    {
        case ARP:  strncpy (text, "ARP" , size);        break;
        case IPV4: strncpy (text, "IPV4", size);        break;
        case IPV6: strncpy (text, "IPV6", size);        break;
        default:   snprintf(text, size, "%04hX", type); break;
    }
}

static void finalisePacket(int action, int type, int dataLength, void* pPacket, int* pSize)
{
    struct header * pHeader = (header*)pPacket;
    
    if (!action) return;

    switch (action)
    {
        case DO_NOTHING:
            return;
        case UNICAST:
        case UNICAST_DNS:
        case UNICAST_DHCP:
            break;
        case MULTICAST_NODE:
            if (type == IPV6) MacMakeMulticastNode6(pHeader->dst);
            else              MacMakeMulticastNode4(pHeader->dst);
            break;
        case MULTICAST_ROUTER:
            if (type == IPV6) MacMakeMulticastRouter6(pHeader->dst);
            else              MacMakeMulticastRouter4(pHeader->dst);
            break;
        case MULTICAST_MDNS:
            if (type == IPV6) MacMakeMulticastMdns6(pHeader->dst);
            else              MacMakeMulticastMdns4(pHeader->dst);
            break;
        case MULTICAST_LLMNR:
            if (type == IPV6) MacMakeMulticastLlmnr6(pHeader->dst);
            else              MacMakeMulticastLlmnr4(pHeader->dst);
            break;
        case BROADCAST:
            MacMakeBroadcast(pHeader->dst);
            break;
        default:
            LogTimeF("Unknown ETH action %d\r\n", action);
            return;
    }
    memcpy(pHeader->src, MacLocal, 6);        //Put our MAC into the source
    pHeader->typ = NetToHost16(type);
    
    *pSize = HEADER_SIZE + dataLength;
}
void LogHeader(struct header* pHeader, char* title)
{
    char text[20];
    LogTimeF("ETH %s\r\n", title);
    NetMacToString(pHeader->dst, sizeof(text), text);
    LogTimeF("Destination:  %s\r\n", text);
    NetMacToString(pHeader->src, sizeof(text), text);
    LogTimeF("Source:       %s\r\n", text);
    typeToString(NetToHost16(pHeader->typ), sizeof(text), text);
    LogTimeF("EtherType:    %s\r\n", text);        
}
int EthHandlePacket(void* pPacket, int* pSize)
{
    struct header * pHeader = (header*)pPacket;
    int dataLength = *pSize - HEADER_SIZE;
    void* pData = (char*)pPacket + HEADER_SIZE;
    
    bool doIt = MacCompareUnicastLocal        (pHeader->dst) || MacCompareBroadcast           (pHeader->dst) ||
                MacCompareMulticastLocal4     (pHeader->dst) || MacCompareMulticastLocal6     (pHeader->dst) ||
                MacCompareMulticastAllNodes4  (pHeader->dst) || MacCompareMulticastAllNodes6  (pHeader->dst) ||
                MacCompareMulticastAllRouters4(pHeader->dst) || MacCompareMulticastAllRouters6(pHeader->dst) ||
                MacCompareMulticastMdns4      (pHeader->dst) || MacCompareMulticastMdns6      (pHeader->dst) ||
                MacCompareMulticastLlmnr4     (pHeader->dst) || MacCompareMulticastLlmnr6     (pHeader->dst);
    
    if (!doIt) return DO_NOTHING;
    
    if (DEBUG) LogHeader(pHeader, "received packet");
    
    uint16_t type = NetToHost16(pHeader->typ);
    if (type < 1500) return DO_NOTHING; //drop 802.3 messages

    int   action = DO_NOTHING;
    switch (type)
    {
        case ARP:  action = ArpHandleReceivedPacket(pHeader->src, pData, &dataLength, pHeader->dst); break;
        case IPV4: action = Ip4HandleReceivedPacket(pHeader->src, pData, &dataLength, pHeader->dst); break;
        case IPV6: action = Ip6HandleReceivedPacket(pHeader->src, pData, &dataLength, pHeader->dst); break;
        default:
            LogHeader(pHeader, "packet not handled");
            break;
    }
    
    finalisePacket(action, type, dataLength, pPacket, pSize);
    return action;
}
int EthPollForPacketToSend(void* pPacket, int* pSize)
{
    struct header * pHeader = (header*)pPacket;
    void* pData = (char*)pPacket + HEADER_SIZE;
    
    int dataLength = 0;
    int type = 0;
    int action = DO_NOTHING;

    if (action == DO_NOTHING)
    {
        action = Ip6PollForPacketToSend(pData, &dataLength, pHeader->dst);
        type = IPV6;
    }
    
    if (action == DO_NOTHING)
    {
        action = Ip4PollForPacketToSend(pData, &dataLength, pHeader->dst);
        type = IPV4;
    }
    
    finalisePacket(action, type, dataLength, pPacket, pSize);
    
    if (DEBUG) LogHeader(pHeader, "sent packet");
    
    return action;
}