Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

ip6/icmp/icmp6.cpp

Committer:
andrewboyson
Date:
2017-10-31
Revision:
48:952dddb74b8b
Parent:
47:73af5c0b0dc2
Child:
49:1a6336f2b3f9

File content as of revision 48:952dddb74b8b:

#include   "mbed.h"
#include    "log.h"
#include    "net.h"
#include "action.h"
#include     "ns.h"
#include     "ra.h"
#include     "rs.h"
#include     "ip.h"
#include    "ip6.h"
#include  "slaac.h"
#include  "echo6.h"

#define HEADER_LENGTH 4
__packed struct header
{
    uint8_t  type;
    uint8_t  code;
    uint16_t checksum;
};
static uint8_t  type;
static uint8_t  code;
static uint16_t checksum;
static uint16_t calculatedChecksum;
static int      dataLength;
static void*    pData;

static void logType(uint8_t type)
{
    switch (type)
    {
        case   1: Log ("Destination uneaceable" ); 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, void* pPacket)
{
    __packed struct pseudo
    {
        char     src[16];
        char     dst[16];
        uint32_t len;
        uint8_t  zer[3];
        uint8_t  pro;
    } pseudo;
    
    Ip6Copy(pseudo.src, pSrcIp);
    Ip6Copy(pseudo.dst, pDstIp);
    pseudo.len    = NetToHost32(size);
    pseudo.zer[0] = 0;
    pseudo.zer[1] = 0;
    pseudo.zer[2] = 0;
    pseudo.pro    = ICMP6;

    return NetCheckSumTwo(sizeof(pseudo), &pseudo, 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);
        LogF("  Data length    %d\r\n",    dataLength);
    }
    else
    {
        Log ("ICMP6 header ");
        logType(type);
        Log("\r\n");
    }
}
static void readHeader(char* pSrcIp, char* pDstIp, void* pPacket, int size)
{
    struct header* pHeader = (header*)pPacket;
                  type =             pHeader->type;
                  code =             pHeader->code;
              checksum = NetToHost16(pHeader->checksum);
    calculatedChecksum = calculateChecksum(pSrcIp, pDstIp, size, pPacket);
                 pData = (char*)pPacket + HEADER_LENGTH;
            dataLength =           size - HEADER_LENGTH;
}
static void writeHeader(void* pPacket, int size, char* pSrcIp, char* pDstIp)
{    
    struct header* pHeader = (header*)pPacket;
    pHeader->type     = type;
    pHeader->code     = code;
    pHeader->checksum = 0;
    checksum = calculateChecksum(pSrcIp, pDstIp, size, pPacket);
    pHeader->checksum = checksum;
    calculatedChecksum = 0;
}
static void (*pTraceBack)(void);
static void trace()
{
    pTraceBack();
    logHeader();
}
int Icmp6HandleReceivedPacket(void (*traceback)(void), int scope, char* pSrcIp, char* pDstIp, int* pSize, void* pPacket)
{
    pTraceBack = traceback;
    
    readHeader(pSrcIp, pDstIp, pPacket, *pSize);

    int action = DO_NOTHING;
    switch (type)
    {
        case 128: //Echo request - Ping
            action = Echo6HandleRequest(trace, &type, &code);
            break;
        case 133: //Router solicit
            return DO_NOTHING; //We are not a router so quietly drop this
        case 134: //Router advertisement
            action = RaHandleReceivedAdvertisement(trace, pData, &dataLength);
            break;
        case 135: //Neighbour solicit
            action = NsHandleReceivedSolicitation(trace, pData, &dataLength, &type, &code);
            break;
        case 136: //Neighbour advertisement
            action = NsHandleReceivedAdvertisement(trace, pData, &dataLength);
            break;
        default:
            LogTimeF("ICMP6 unknown packet type %d\r\n", type);
            return DO_NOTHING;
    }
    if (!action) return DO_NOTHING;
    
    Ip6Copy(pDstIp, pSrcIp);
    Ip6SrcIpFromScope(scope,                     pSrcIp);
    Ip6DstIpFromDest (ActionGetDestPart(action), pDstIp);

    *pSize = HEADER_LENGTH + dataLength;
    
    writeHeader(pPacket, *pSize, pSrcIp, pDstIp);
    
    if (ActionGetTracePart(action)) logHeader();
    
    return action;
}
int Icmp6PollForPacketToSend(void* pPacket, int* pSize, char* pSrcIp, char* pDstIp)
{    
    pData = (char*)pPacket + 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;
    Ip6SrcIpFromScope(scope,                     pSrcIp);
    Ip6DstIpFromDest (ActionGetDestPart(action), pDstIp);

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

}