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-11-28
Revision:
57:e0fb648acf48
Parent:
47:73af5c0b0dc2
Child:
59:e0e556c8bd46

File content as of revision 57:e0fb648acf48:

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

#define HEADER_SIZE 14

//header variables
__packed struct header
{
    char     dst[6];
    char     src[6];
    uint16_t typ;
};
static uint16_t protocol;
void EthProtocolLog(uint16_t prototype)
{
    switch (prototype)
    {
        case ARP:  Log("ARP");               break;
        case IPV4: Log("IPV4");              break;
        case IPV6: Log("IPV6");              break;
        default:   LogF("%04hX", prototype); break;
    }
}

static void finalisePacket(int dest, int dataLength, void* pPacket, int* pSize)
{
    if (!dest) return;
    
    struct header * pHeader = (header*)pPacket;
        
    MacMakeFromDest(dest, protocol, pHeader->dst);

    MacCopy(pHeader->src, MacLocal);        //Put our MAC into the source
    pHeader->typ = NetToHost16(protocol);
    
    *pSize = HEADER_SIZE + dataLength;
}
void LogHeader(struct header* pHeader)
{
    if (NetTraceVerbose)
    {
        Log("ETH header\r\n");
        Log("  Destination:  ");         MacLog(pHeader->dst);              Log("\r\n");
        Log("  Source:       ");         MacLog(pHeader->src);              Log("\r\n");
        Log("  EtherType:    "); EthProtocolLog(NetToHost16(pHeader->typ)); Log("\r\n");        
    }
    else
    {
        Log("ETH   header ");
        EthProtocolLog(NetToHost16(pHeader->typ));
        Log(" ");
        MacLog(pHeader->src);
        Log(" >>> ");
        MacLog(pHeader->dst);
        Log("\r\n");
    }
}
static void (*pTraceBack)(void);
static void* tracePacket;
static void trace()
{
    pTraceBack();
    struct header * pHeader = (header*)tracePacket;
    LogHeader(pHeader);
}
int EthHandlePacket(void (*traceback)(void), void* pPacket, int* pSize)
{
    pTraceBack = traceback;
    tracePacket = pPacket;
    struct header * pHeader = (header*)pPacket;
    int dataLength = *pSize - HEADER_SIZE;
    void* pData = (char*)pPacket + HEADER_SIZE;
        
    if (!MacAccept(pHeader->dst)) return DO_NOTHING;
    
    protocol = NetToHost16(pHeader->typ);
    if (protocol < 1500) return DO_NOTHING; //drop 802.3 messages

    NetTraceHostCheckMac(pHeader->src);

    int   action = DO_NOTHING;
    switch (protocol)
    {
        case ARP:  action = ArpHandleReceivedPacket(trace, pHeader->src, pData, &dataLength, pHeader->dst); break;
        case IPV4: action = Ip4HandleReceivedPacket(trace, pHeader->src, pData, &dataLength, pHeader->dst); break;
        case IPV6: action = Ip6HandleReceivedPacket(trace, pHeader->src, pData, &dataLength, pHeader->dst); break;
        case 0x6970: break; //Drop Sonos group membership packet
        case 0x7374: break; //Drop Sky Q packet
        case 0x7475: break; //Drop Sky Q packet
        case 0x7380: break; //Drop Sky Q packet
        case 0x8100: break; //Drop Sky Q VLAN 802.1Q packet
        case 0x887b: break; //Drop Sky Q packet
        default:
            LogTimeF("ETH protocol %d not handled", protocol);
            break;
    }
    if (!action) return DO_NOTHING;
    
    finalisePacket(ActionGetDestPart(action), dataLength, pPacket, pSize);
    
    if (ActionGetTracePart(action)) LogHeader(pHeader);
    
    return action;
}
int EthPollForPacketToSend(void* pPacket, int* pSize)
{
    struct header * pHeader = (header*)pPacket;
    void* pData = (char*)pPacket + HEADER_SIZE;
    
    int dataLength = 0;
    protocol = 0;
    int action = DO_NOTHING;

    if (!action)
    {
        action = ArpPollForPacketToSend(pData, &dataLength);
        protocol = ARP;
    }

    if (!action)
    {
        action = Ip6PollForPacketToSend(pData, &dataLength, pHeader->dst);
        protocol = IPV6;
    }
    
    if (!action)
    {
        action = Ip4PollForPacketToSend(pData, &dataLength, pHeader->dst);
        protocol = IPV4;
    }
    
    if (!action) return DO_NOTHING;
    
    finalisePacket(ActionGetDestPart(action), dataLength, pPacket, pSize);
    
    if (ActionGetTracePart(action)) LogHeader(pHeader);
    
    return action;
}