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

ip6/icmp/icmp6.c

Committer:
andrewboyson
Date:
2020-04-02
Revision:
167:3ba4e3c49631
Parent:
138:5ff0c7069300
Child:
172:9bc3c7b2cca1

File content as of revision 167:3ba4e3c49631:

#include <stdint.h>

#include     "log.h"
#include     "net.h"
#include  "action.h"
#include      "ns.h"
#include      "ra.h"
#include      "rs.h"
#include      "ip.h"
#include "ip6addr.h"
#include   "slaac.h"
#include   "echo6.h"
#include   "dest6.h"
#include "checksum.h"

static char* hdrPtrType    (char* pPacket) { return pPacket + 0; } //1
static char* hdrPtrCode    (char* pPacket) { return pPacket + 1; } //1
static char* hdrPtrChecksum(char* pPacket) { return pPacket + 2; } //2
static const int HEADER_LENGTH = 4;

static uint8_t  type;
static uint8_t  code;
static uint16_t checksum;
static uint16_t calculatedChecksum;

static void logType(uint8_t type)
{
    switch (type)
    {
        case   1: Log ("Destination unreacheable" ); break;
        case 128: Log ("Echo Request"             ); break;
        case 129: Log ("Echo Reply"               ); break;
        case 133: Log ("Router solicit"           ); break;
        case 134: Log ("Router advertisement"     ); break;
        case 135: Log ("Neighbour solicit"        ); break;
        case 136: Log ("Neighbour advertisement"  ); break;
        case 137: Log ("Redirect"                 ); break;
        default:  LogF("Unknown type %u", type    ); break;
    }
}
static uint16_t calculateChecksum(char* pSrcIp, char* pDstIp, int size, char* pPacket)
{   
    uint32_t sum = 0;
    uint32_t pro32 = ICMP6;
     sum = CheckSumAddDirect(sum,   16, pSrcIp );
     sum = CheckSumAddDirect(sum,   16, pDstIp );
     sum = CheckSumAddInvert(sum,    4, &size  );
     sum = CheckSumAddInvert(sum,    4, &pro32 );
    return CheckSumFinDirect(sum, size, pPacket);
}
static void logHeader()
{
    if (NetTraceVerbose)
    {
        Log ("ICMP6 header\r\n");
        Log ("  Type           "); logType(type); Log("\r\n");
        LogF("  Code           %u\r\n",    code);
        LogF("  Checksum (hex) %04hX\r\n", checksum);
        LogF("  Calculated     %04hX\r\n", calculatedChecksum);
    }
    else
    {
        Log ("ICMP6 header ");
        logType(type);
        Log("\r\n");
    }
}
static void readHeader(char* pSrcIp, char* pDstIp, char* pPacket, int size)
{
    type = *hdrPtrType(pPacket);
    code = *hdrPtrCode(pPacket);
    NetDirect16(&checksum, hdrPtrChecksum(pPacket));
    calculatedChecksum = calculateChecksum(pSrcIp, pDstIp, size, pPacket);
}
static void writeHeader(char* pPacket, int size, char* pSrcIp, char* pDstIp)
{
    *hdrPtrType(pPacket) = type;
    *hdrPtrCode(pPacket) = code;
    checksum = 0;
    NetDirect16(hdrPtrChecksum(pPacket), &checksum);
    checksum = calculateChecksum(pSrcIp, pDstIp, size, pPacket);
    NetDirect16(hdrPtrChecksum(pPacket), &checksum);
    calculatedChecksum = 0;
}
static void (*pTraceBack)(void);
static void trace()
{
    pTraceBack();
    logHeader();
}
int Icmp6HandleReceivedPacket(void (*traceback)(void), int scope, char* pPacketRx, int sizeRx, char* pPacketTx, int* pSizeTx, char* pSrcIp, char* pDstIp)
{
    pTraceBack = traceback;
        
    readHeader(pSrcIp, pDstIp, pPacketRx, sizeRx);
    
    int dataLengthRx =    sizeRx - HEADER_LENGTH;
    int dataLengthTx =  *pSizeTx - HEADER_LENGTH;
    char* pPayloadRx = pPacketRx + HEADER_LENGTH;
    char* pPayloadTx = pPacketTx + HEADER_LENGTH;

    int action = DO_NOTHING;
    switch (type)
    {
        case   1: //Destination unreacheable
            action = Dest6HandleRequest(trace, &type, &code);
            break;
        case 128: //Echo request - Ping
            action = Echo6HandleRequest(trace, &type, &code, pPayloadRx, dataLengthRx, pPayloadTx, &dataLengthTx);
            break;
        case 133: //Router solicit
            return DO_NOTHING; //We are not a router so quietly drop this
        case 134: //Router advertisement
            action = RaHandleReceivedAdvertisement(trace, pPayloadRx, &dataLengthRx);
            break;
        case 135: //Neighbour solicit
            action = NsHandleReceivedSolicitation(trace, &type, &code, pPayloadRx, dataLengthRx, pPayloadTx, &dataLengthTx);
            break;
        case 136: //Neighbour advertisement
            action = NsHandleReceivedAdvertisement(trace, pPayloadRx, &dataLengthRx);
            break;
        default:
            LogTimeF("ICMP6 unknown packet type %d\r\n", type);
            return DO_NOTHING;
    }
    if (!action) return DO_NOTHING;
    
    Ip6AddressCopy(pDstIp, pSrcIp);
    SlaacAddressFromScope(scope,                     pSrcIp);
      Ip6AddressFromDest (ActionGetDestPart(action), pDstIp);

    *pSizeTx = HEADER_LENGTH + dataLengthTx;
    
    writeHeader(pPacketTx, *pSizeTx, pSrcIp, pDstIp);
    
    if (ActionGetTracePart(action)) logHeader();
    
    return action;
}
int Icmp6PollForPacketToSend(char* pPacket, int* pSize, char* pSrcIp, char* pDstIp)
{    
    char* pData    = pPacket + HEADER_LENGTH;
    int dataLength =  *pSize - HEADER_LENGTH;
    int action  = DO_NOTHING;
    if (!action) action = RsGetWaitingSolicitation(pData, &dataLength, &type, &code);
    if (!action) action = NsGetWaitingSolicitation(pData, &dataLength, &type, &code);
    if (!action) return DO_NOTHING;

    int scope = SCOPE_LOCAL;
    SlaacAddressFromScope(scope,                     pSrcIp);
      Ip6AddressFromDest (ActionGetDestPart(action), pDstIp);

    *pSize = HEADER_LENGTH + dataLength;
    
    writeHeader(pPacket, *pSize, pSrcIp, pDstIp);
    
    if (ActionGetTracePart(action)) logHeader();
    
    return action;

}