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/ip6.c

Committer:
andrewboyson
Date:
2018-10-20
Revision:
71:736a5747ade1
Parent:
61:aad055f1b0d1
Child:
74:c3756bfa960e

File content as of revision 71:736a5747ade1:

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

#include     "log.h"
#include     "net.h"
#include  "action.h"
#include   "icmp6.h"
#include "udptcp6.h"
#include     "ar6.h"
#include     "nr6.h"
#include   "slaac.h"
#include     "eth.h"
#include      "ip.h"
#include "ip6addr.h"
#include     "ndp.h"
#include     "ntp.h"
#include     "mac.h"
#include    "http.h"

bool Ip6Trace = true;

__packed struct header
{
    uint32_t versionTrafficFlow;
    uint16_t payloadLength;
    uint8_t  protocol;
    uint8_t  hoplimit;
    char     src[16];
    char     dst[16];
};

static uint8_t     version;
static int   payloadLength;
static uint8_t    protocol;
static uint8_t    hoplimit;
static char      srcIp[16];
static char      dstIp[16];

static void readHeader(struct header * pHeader)
{
    version    =            (pHeader->versionTrafficFlow >> 4) & 0x0F;
 payloadLength = NetToHost16(pHeader->payloadLength);
    protocol   =             pHeader->protocol;
    hoplimit   =             pHeader->hoplimit;
       Ip6AddressCopy(srcIp, pHeader->src);
       Ip6AddressCopy(dstIp, pHeader->dst);
}
static void writeHeader(struct header * pHeader)
{
                   pHeader->versionTrafficFlow  = version << 4;
                   pHeader->payloadLength       = NetToHost16(payloadLength);
                   pHeader->protocol            = protocol;
                   pHeader->hoplimit            = hoplimit;
    Ip6AddressCopy(pHeader->dst, dstIp);
    Ip6AddressCopy(pHeader->src, srcIp);
}

static void logHeader()
{
    if (NetTraceVerbose)
    {
        Log("IP6 header\r\n");
        LogF("  Version           %d\r\n", version);
        LogF("  Payload length    %d\r\n", payloadLength);
        LogF("  Hop limit         %d\r\n", hoplimit);
        LogF("  Protocol          "); IpProtocolLog(protocol); Log("\r\n");
        Log ("  Source IP         "); Ip6AddressLog(srcIp);    Log("\r\n");
        Log ("  Destination IP    "); Ip6AddressLog(dstIp);    Log("\r\n");
    }
    else
    {
        Log("IP6   header ");
        IpProtocolLog(protocol);
        Log(" ");
        Ip6AddressLog(srcIp);
        Log(" >>> ");
        Ip6AddressLog(dstIp);
        Log("\r\n");
    }
}

static bool getIsSolicited(char* p)
{
    if (*p++ != 0xff) return false;
    if (*p++ != 0x02) return false;
    
    if (*p++ != 0x00) return false;
    if (*p++ != 0x00) return false;
    
    if (*p++ != 0x00) return false;
    if (*p++ != 0x00) return false;
    
    if (*p++ != 0x00) return false;
    if (*p++ != 0x00) return false;
    
    if (*p++ != 0x00) return false;
    if (*p++ != 0x00) return false;
    
    if (*p++ != 0x00) return false;
    if (*p++ != 0x01) return false;
    
    if (*p++ != 0xff) return false;
    
    return true;
}
static bool getIsSameGroup(char* pA, char* pB)
{
    pA += 13;
    pB += 13;
    if (*pA++ != *pB++) return false;
    if (*pA++ != *pB++) return false;
    return *pA == *pB;
}
static void (*pTraceBack)(void);
static void trace()
{
    pTraceBack();
    logHeader();
}
int Ip6HandleReceivedPacket(void (*traceback)(void), void* pPacketRx, int sizeRx, void* pPacketTx, int* pSizeTx, char* macRemote)
{
    pTraceBack = traceback;
    
    struct header* pHeaderRx = (struct header*)pPacketRx;
    struct header* pHeaderTx = (struct header*)pPacketTx;
    
    char* pDataRx = (char*)pHeaderRx + sizeof(struct header);
    char* pDataTx = (char*)pHeaderTx + sizeof(struct header);
    
    readHeader(pHeaderRx); //This also fetches the payload length out of the header
    
    int dataLengthRx = sizeRx - sizeof(struct header);
    if (payloadLength < dataLengthRx) dataLengthRx = payloadLength; //Choose the lesser of the data length and the payload length
    int dataLengthTx = *pSizeTx - sizeof(struct header);
    
    int  scope       = SlaacScope(dstIp);
    bool isMe        = scope != SCOPE_NONE;
    bool isMulticast = dstIp[0] == 0xFF;
    bool isSolicited = getIsSolicited(dstIp);
    bool isGroup     = getIsSameGroup(dstIp, SlaacLinkLocalIp);
    
    bool doIt = isMe || (isMulticast && !isSolicited) || (isGroup && isSolicited);
    
    if (!doIt)
    {
        if (Ip6Trace)
        {
            LogTime("IP6 filtered out ip ");
            Ip6AddressLog(dstIp);
            LogF(" from ");
            Ip6AddressLog(srcIp);
            Log("\r\n");
        }
        return DO_NOTHING;
    }
    
    NetTraceHostCheckIp6(srcIp);
    
    char* pCachedRemIp = Ar6AddIpRecord(trace, macRemote, srcIp);
    Nr6MakeRequestForNameFromIp(srcIp);

    int action = DO_NOTHING;
    switch (protocol)
    {
        case HOPOPT: action = DO_NOTHING;                                                                                           break;
        case ICMP6:  action = Icmp6HandleReceivedPacket(trace, scope, pDataRx, dataLengthRx, pDataTx, &dataLengthTx, srcIp, dstIp); break;
        case UDP:    action =  Udp6HandleReceivedPacket(trace, scope, pDataRx, dataLengthRx, pDataTx, &dataLengthTx, srcIp, dstIp); break;
        case TCP:    action =  Tcp6HandleReceivedPacket(trace, scope, pDataRx, dataLengthRx, pDataTx, &dataLengthTx, srcIp, dstIp, pCachedRemIp); break;        
        default:
            LogTimeF("IP6 protocol %d unhandled\r\n", protocol);
            return DO_NOTHING;
    }
    if (!action) return DO_NOTHING;
    
    if (NdpIpNeedsToBeRouted(dstIp))
    {
        MacCopy(macRemote, NdpRouterMac); //Send to the router MAC
        hoplimit = NdpHopLimit;
    }
    else
    {
        hoplimit = 255;
    }
    
    payloadLength = dataLengthTx;

    writeHeader(pHeaderTx);
      
    *pSizeTx = sizeof(struct header) + payloadLength;
    
    if (ActionGetTracePart(action)) logHeader();

    return action;
}
int Ip6PollForPacketToSend(void* pPacket, int* pSize, char* pDstMac)
{    
    char* pData = (char*)pPacket + sizeof(struct header);
    int dataLength = *pSize - sizeof(struct header);
    
    int action = DO_NOTHING;
    if (!action) { action = Icmp6PollForPacketToSend(pData, &dataLength, srcIp, dstIp); protocol = ICMP6; }
    if (!action) { action =  Udp6PollForPacketToSend(pData, &dataLength, srcIp, dstIp); protocol = UDP;   }
    if (!action) { action =  Tcp6PollForPacketToSend(pData, &dataLength, srcIp, dstIp); protocol = TCP;   }
    if (!action) return DO_NOTHING;
    
    int dest = ActionGetDestPart(action);
    switch (dest)
    {
        case UNICAST:
        case UNICAST_DNS:
        case UNICAST_DHCP:
        case UNICAST_NTP:
        case UNICAST_TFTP:
            if (NdpIpNeedsToBeRouted(dstIp))
            {
                MacCopy(pDstMac, NdpRouterMac); //Send to the router MAC
                hoplimit = NdpHopLimit;
            }
            else
            {
                Ar6IpToMac(dstIp, pDstMac); //Make the remote MAC from NP
                hoplimit = 255;
            }
            break;
        case MULTICAST_NODE:
        case MULTICAST_ROUTER:
        case MULTICAST_MDNS:
        case MULTICAST_LLMNR:
        case SOLICITED_NODE:
            hoplimit = 255;
            break;
        default:
            LogTimeF("Ip6PollForPacketToSend - undefined destination %d\r\n", dest);
            return DO_NOTHING;
    }

    payloadLength  = dataLength;
    version        = 6;
    writeHeader((struct header*)pPacket);

    *pSize = sizeof(struct header) + payloadLength;
    
    if (ActionGetTracePart(action)) logHeader();

    return action;
}