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-07-24
Revision:
28:edc17eeb4142
Parent:
23:b641979389b2
Child:
33:714a0345e59b

File content as of revision 28:edc17eeb4142:

#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;
};

uint16_t EthProtocol;

void EthProtocolToString(uint16_t prototype, int size, char* text)
{
    switch (prototype)
    {
        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", prototype); break;
    }
}

static void finalisePacket(int action, int dataLength, void* pPacket, int* pSize)
{
    if (!action) return;
    
    struct header * pHeader = (header*)pPacket;
        
    MacMake(action, EthProtocol, pHeader->dst);

    memcpy(pHeader->src, MacLocal, 6);        //Put our MAC into the source
    pHeader->typ = NetToHost16(EthProtocol);
    
    *pSize = HEADER_SIZE + dataLength;
}
void LogHeader(struct header* pHeader, char* title)
{
    char text[20];
    LogTimeF("ETH %s\r\n", title);
    MacToString(pHeader->dst, sizeof(text), text);
    LogTimeF("Destination:  %s\r\n", text);
    MacToString(pHeader->src, sizeof(text), text);
    LogTimeF("Source:       %s\r\n", text);
    EthProtocolToString(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;
        
    if (!MacAccept(pHeader->dst)) return DO_NOTHING;
    
    if (DEBUG) LogHeader(pHeader, "received packet");
    
    EthProtocol = NetToHost16(pHeader->typ);
    if (EthProtocol < 1500) return DO_NOTHING; //drop 802.3 messages

    int   action = DO_NOTHING;
    switch (EthProtocol)
    {
        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;
        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
        default:
            LogHeader(pHeader, "packet not handled");
            break;
    }
    
    finalisePacket(action, 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;
    EthProtocol = 0;
    int action = DO_NOTHING;

    if (action == DO_NOTHING)
    {
        action = ArpPollForPacketToSend(pData, &dataLength);
        EthProtocol = ARP;
    }

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