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

arp/arp.c

Committer:
andrewboyson
Date:
2018-12-05
Revision:
94:e2973a2c488e
Parent:
61:aad055f1b0d1
Child:
136:8a65abb0dc63

File content as of revision 94:e2973a2c488e:

#include <stdint.h>
#include <stdbool.h>

#include    "log.h"
#include "action.h"
#include    "net.h"
#include    "eth.h"
#include    "mac.h"
#include   "dhcp.h"
#include    "ar4.h"
#include    "nr4.h"
#include "ip4addr.h"

#define REQUEST   1
#define REPLY     2

bool ArpTrace = false;

uint32_t ArpAddressToResolve;
bool     ArpResolveRequestFlag = false;

__packed struct header
{
    int16_t  hardwareType;             //16.bit: (ar$hrd) Hardware address space (e.g., Ethernet, Packet Radio Net). Always 1.
    int16_t  protocolType;             //16.bit: (ar$pro) Protocol address space.  For Ethernet hardware, this is from the set of type fields ether_typ$<protocol>. As held in eth.h, eg IPv4 = 0x8000.
    int8_t   hardwareLength;           // 8.bit: (ar$hln) byte length of each hardware address. Always 6 bytes.
    int8_t   protocolLength;           // 8.bit: (ar$pln) byte length of each protocol address. Always 4 bytes.
    int16_t  opCode;                   //16.bit: (ar$op)  opcode (ares_op$REQUEST = 1 | ares_op$REPLY = 2), high byte transmitted first.
    char     senderHardwareAddress[6]; //nbytes: (ar$sha) Hardware address of sender of this packet, n from the ar$hln field.
    uint32_t senderProtocolAddress;    //mbytes: (ar$spa) Protocol address of sender of this packet, m from the ar$pln field.
    char     targetHardwareAddress[6]; //nbytes: (ar$tha) Hardware address of target of this packet (if known).
    uint32_t targetProtocolAddress;    //mbytes: (ar$tpa) Protocol address of target.
};

static void logHeader(struct header* pHeader)
{    
    if (NetTraceVerbose)
    {
        LogTime("ARP header\r\n");
        if (NetToHost16(pHeader->hardwareType) == ETHERNET) Log ("  hardwareType          = ETHERNET\r\n");
        else                                                LogF("  hardwareType          = %d\r\n", NetToHost16(pHeader->hardwareType));
        Log ("  protocolType          = ");      EthProtocolLog(pHeader->protocolType);          Log("\r\n");
        LogF("  hardwareLength        = %d\r\n",                pHeader->hardwareLength);
        LogF("  protocolLength        = %d\r\n",                pHeader->protocolLength);
        if      (NetToHost16(pHeader->opCode) == REQUEST)   Log ("  opCode                = REQUEST\r\n");
        else if (NetToHost16(pHeader->opCode) == REPLY  )   Log ("  opCode                = REPLY\r\n");
        else                                                LogF("  opCode                = %d\r\n", NetToHost16(pHeader->opCode));
        Log("  senderHardwareAddress = ");               MacLog(pHeader->senderHardwareAddress); Log("\r\n");
        Log("  senderProtocolAddress = ");        Ip4AddressLog(pHeader->senderProtocolAddress); Log("\r\n");
        Log("  targetHardwareAddress = ");               MacLog(pHeader->targetHardwareAddress); Log("\r\n");
        Log("  targetProtocolAddress = ");        Ip4AddressLog(pHeader->targetProtocolAddress); Log("\r\n");
    }
    else
    {
        Log("ARP header ");
               MacLog(pHeader->senderHardwareAddress); Log("==");
        Ip4AddressLog(pHeader->senderProtocolAddress); Log(" >>> ");
               MacLog(pHeader->targetHardwareAddress); Log("==");
        Ip4AddressLog(pHeader->targetProtocolAddress); Log("\r\n");
        
    }
}
static struct header* pHeaderTrace;
static void (*pTraceBack)(void);
static void trace()
{
    pTraceBack();
    logHeader(pHeaderTrace);
}

int ArpHandleReceivedPacket(void (*traceback)(void), void* pPacketRx, int sizeRx, void* pPacketTx, int* pSizeTx)
{
    pTraceBack = traceback;
    struct header* pHeaderRx = (struct header*)pPacketRx;
    struct header* pHeaderTx = (struct header*)pPacketTx;
    pHeaderTrace = pHeaderRx;
    
    int16_t           hardwareType = NetToHost16(pHeaderRx->hardwareType);
    int16_t           protocolType = NetToHost16(pHeaderRx->protocolType);
    int8_t          hardwareLength =             pHeaderRx->hardwareLength;
    int8_t          protocolLength =             pHeaderRx->protocolLength;
    int16_t                 opCode = NetToHost16(pHeaderRx->opCode);
    uint32_t targetProtocolAddress =             pHeaderRx->targetProtocolAddress;

    if (hardwareType          != ETHERNET     ) return DO_NOTHING; //This is not ethernet
    if (protocolType          != IPV4         ) return DO_NOTHING; //This is not IPv4
    if (hardwareLength        != 6            ) return DO_NOTHING; //This is not a MAC hardware address
    if (protocolLength        != 4            ) return DO_NOTHING; //This is not an IPv4 IP address
    if (targetProtocolAddress != DhcpLocalIp  ) return DO_NOTHING; //This packet was not addressed to us
    
    switch (opCode)
    {
        case REQUEST:
            if (ArpTrace)
            {
                if (NetTraceNewLine) Log("\r\n");
                LogTime("ARP received request\r\n");
                if (NetTraceStack) traceback();
                logHeader(pHeaderRx);
            }   
                    pHeaderTx->hardwareType          = NetToHost16(ETHERNET);
                    pHeaderTx->protocolType          = NetToHost16(IPV4);
                    pHeaderTx->hardwareLength        = 6;
                    pHeaderTx->protocolLength        = 4;
                    pHeaderTx->opCode                = NetToHost16(REPLY);
            MacCopy(pHeaderTx->targetHardwareAddress,  pHeaderRx->senderHardwareAddress);
                    pHeaderTx->targetProtocolAddress = pHeaderRx->senderProtocolAddress;
            MacCopy(pHeaderTx->senderHardwareAddress,  MacLocal);
                    pHeaderTx->senderProtocolAddress = DhcpLocalIp;
            *pSizeTx = sizeof(struct header);
            if (ArpTrace) logHeader(pHeaderTx);
            return ActionMakeFromDestAndTrace(UNICAST, ArpTrace && NetTraceStack);
            
        case REPLY:
            if (ArpTrace)
            {
                if (NetTraceNewLine) Log("\r\n");
                LogTime("ARP received reply\r\n");
                if (NetTraceStack) traceback();
                logHeader(pHeaderRx);
            }   
            Ar4AddIpRecord(trace, pHeaderRx->senderHardwareAddress, pHeaderRx->senderProtocolAddress);
            Nr4MakeRequestForNameFromIp(pHeaderRx->senderProtocolAddress);
            return DO_NOTHING;
            
        default:
            return DO_NOTHING;
    }
}
int ArpPollForPacketToSend(void* pPacketTx, int* pSizeTx)
{
    if (!ArpResolveRequestFlag) return DO_NOTHING;
    ArpResolveRequestFlag = false;

    struct header* pHeaderTx = (struct header*)pPacketTx;

    pHeaderTx->hardwareType   = NetToHost16(ETHERNET);
    pHeaderTx->protocolType   = NetToHost16(IPV4);
    pHeaderTx->hardwareLength = 6;
    pHeaderTx->protocolLength = 4;
    pHeaderTx->opCode         = NetToHost16(REQUEST);

    MacClear(pHeaderTx->targetHardwareAddress);
             pHeaderTx->targetProtocolAddress = ArpAddressToResolve;
    MacCopy (pHeaderTx->senderHardwareAddress,  MacLocal);
             pHeaderTx->senderProtocolAddress = DhcpLocalIp;

    *pSizeTx = sizeof(struct header);
    
    if (ArpTrace)
    {
        if (NetTraceNewLine) Log("\r\n");
        LogTime("ARP send request\r\n");
        logHeader(pHeaderTx);
    }
    return ActionMakeFromDestAndTrace(BROADCAST, ArpTrace && NetTraceStack);
}