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

udp/udp.c

Committer:
andrewboyson
Date:
2020-04-02
Revision:
167:3ba4e3c49631
Parent:
142:a8c0890a58d1
Child:
171:f708d6776752

File content as of revision 167:3ba4e3c49631:

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

#include "log.h"
#include "net.h"
#include "action.h"
#include "udp.h"
#include "ntp.h"
#include "tftp.h"
#include "dhcp.h"
#include "dns.h"
#include "eth.h"
#include "ip4.h"
#include "ip6.h"
#include "slaac.h"
#include "ns.h"
#include "ntpclient.h"
#include "restart.h"

bool UdpTrace = true;

static char* hdrPtrSrcPort    (char* pPacket) { return pPacket + 0; } //2
static char* hdrPtrDstPort    (char* pPacket) { return pPacket + 2; } //2
static char* hdrPtrTotalLength(char* pPacket) { return pPacket + 4; } //2
static char* hdrPtrChecksum   (char* pPacket) { return pPacket + 6; } //2
static const int HEADER_LENGTH = 8;

void UdpHdrSetChecksum(void* pPacket, uint16_t checksum)
{
    NetDirect16(hdrPtrChecksum(pPacket), &checksum);
}
static uint16_t     srcPort;
static uint16_t     dstPort;
static uint16_t    checksum;
static uint16_t totalLength;

static void readHeader(char* pPacket)
{
    NetInvert16(&srcPort,     hdrPtrSrcPort    (pPacket));
    NetInvert16(&dstPort,     hdrPtrDstPort    (pPacket));
    NetDirect16(&checksum,    hdrPtrChecksum   (pPacket));
    NetInvert16(&totalLength, hdrPtrTotalLength(pPacket));
}
void UdpMakeHeader(int size, char* pPacket)
{
    checksum = 0;
    NetInvert16(hdrPtrSrcPort    (pPacket), &srcPort    );
    NetInvert16(hdrPtrDstPort    (pPacket), &dstPort    );
    NetDirect16(hdrPtrChecksum   (pPacket), &checksum   );
    NetInvert16(hdrPtrTotalLength(pPacket), &size       );

}

void UdpLogHeader(uint16_t calculatedChecksum)
{
    if (NetTraceVerbose)
    {
        Log ("UDP header\r\n");
        LogF("  Source port      %hu\r\n", srcPort);
        LogF("  Destination port %hu\r\n", dstPort);
        LogF("  Total length     %hu\r\n", totalLength);
        LogF("  Checksum (hex)   %04hX\r\n", checksum);
        LogF("  Calculated       %04hX\r\n", calculatedChecksum);
    }
    else
    {
        LogF("UDP   header %hu >>> %hu\r\n", srcPort, dstPort);
    }
}

static int handlePort(void (*traceback)(void), int dataLengthRx, char* pDataRx, int* pPataLengthTx, char* pDataTx)
{
    switch (dstPort)
    {
        //Handle these
        case DHCP_CLIENT_PORT:          return DhcpHandleResponse      (traceback,                     dataLengthRx, pDataRx, pPataLengthTx, pDataTx);  //   68
        case NTP_PORT:                  return  NtpHandlePacketReceived(traceback,                     dataLengthRx, pDataRx, pPataLengthTx, pDataTx);  //  123
        case DNS_UNICAST_CLIENT_PORT:   return  DnsHandlePacketReceived(traceback, DNS_PROTOCOL_UDNS,  dataLengthRx, pDataRx, pPataLengthTx, pDataTx);  //53053
        case DNS_MDNS_PORT:             return  DnsHandlePacketReceived(traceback, DNS_PROTOCOL_MDNS,  dataLengthRx, pDataRx, pPataLengthTx, pDataTx);  // 5353
        case DNS_LLMNR_CLIENT_PORT:     return  DnsHandlePacketReceived(traceback, DNS_PROTOCOL_LLMNR, dataLengthRx, pDataRx, pPataLengthTx, pDataTx);  //53055
        case DNS_LLMNR_SERVER_PORT:     return  DnsHandlePacketReceived(traceback, DNS_PROTOCOL_LLMNR, dataLengthRx, pDataRx, pPataLengthTx, pDataTx);  // 5355
        case TFTP_CLIENT_PORT:          return TftpHandlePacketReceived(traceback,                     dataLengthRx, pDataRx, pPataLengthTx, pDataTx);  //60690
        
        //Quietly drop these
        case DHCP_SERVER_PORT:  //67
        case TFTP_SERVER_PORT:  //69
        case   137:             //NETBIOS name service
        case   138:             //NETBIOS datagram service
        case   139:             //NETBIOS session service
        case   500:             //Key exchange - Xbox live                  
        case  1900:             //SSDP Simple Service Discovery Protocol (uPnP)
        case  3074:             //Xbox live
        case  3076:             //Call of Duty - Xbox
        case  5050:             //Don't know but have been sent by Kate and my android phones.
        case  5224:             //Don't know but a burst was broadcast by Kate's phone containing '_logitech-reverse-bonjour._tcp.local.5446 192.168.1.36 string'
        case  9956:             //Alljoyn part of Allseen IoT services
        case  9997:             //VLC
        case  9998:             //VLC
        case  9999:             //VLC
        case 17500:             //Dropbox LAN sync
        case 57621:             //Spotify P2P
            return DO_NOTHING;
            
        //Report anything else
        default:
            if (UdpTrace)
            {
                LogTimeF("UDP unknown port %d\r\n", dstPort);
                traceback(); //This will already include the UDP header
            }
            return DO_NOTHING;
    }
}
int UdpHandleReceivedPacket(void (*traceback)(void), int sizeRx, char* pPacketRx, int* pSizeTx, char* pPacketTx)
{    
    int lastRestartPoint = RestartPoint;
    RestartPoint = FAULT_POINT_UdpHandleReceivedPacket;
    
    readHeader(pPacketRx);

    void* pDataRx    = pPacketRx + HEADER_LENGTH;
    void* pDataTx    = pPacketTx + HEADER_LENGTH;
    int dataLengthRx =    sizeRx - HEADER_LENGTH;
    int dataLengthTx =  *pSizeTx - HEADER_LENGTH;
    
    int action = handlePort(traceback, dataLengthRx, pDataRx, &dataLengthTx, pDataTx);
    
    *pSizeTx = dataLengthTx + HEADER_LENGTH;
    
    uint16_t tmpPort = dstPort;
    dstPort = srcPort;
    srcPort = tmpPort;
    
    RestartPoint = lastRestartPoint;
    return action;
}
static int pollForPacketToSend(int type, int* pDataLength, char* pData)
{
    int action = DO_NOTHING;
    
    if (!action && type == IPV4) //DHCP only works under IPv4
    {
        action = DhcpPollForRequestToSend(pData, pDataLength);
        if (action)
        {
            srcPort = DHCP_CLIENT_PORT;
            dstPort = DHCP_SERVER_PORT;
        }
    }
    
    if (!action && type == (DnsSendRequestsViaIp4 ? IPV4 : IPV6)) //DNS is agnostic
    {
        action = DnsPollForPacketToSend(pData, pDataLength);
        int dest = ActionGetDestPart(action);
        if (dest)
        {
            switch (dest)
            {
                case   UNICAST_DNS:    srcPort = DNS_UNICAST_CLIENT_PORT;   dstPort = DNS_UNICAST_SERVER_PORT;   break; //53053,   53
                case MULTICAST_MDNS:   srcPort = DNS_MDNS_PORT;             dstPort = DNS_MDNS_PORT;             break; // 5353, 5353
                case MULTICAST_LLMNR:  srcPort = DNS_LLMNR_CLIENT_PORT;     dstPort = DNS_LLMNR_SERVER_PORT;     break; //53055, 5355
                
                //Report anything else
                default:
                    LogTimeF("DNS unknown dest %d\r\n", dest);
                    return DO_NOTHING;
            }
        }
    }
    if (!action && type == (NtpClientQuerySendRequestsViaIp4 ? IPV4 : IPV6)) //NTP is agnostic
    {
        action = NtpPollForPacketToSend(type, pData, pDataLength);
        if (action)
        {
            srcPort = NTP_PORT;
            dstPort = NTP_PORT;
        }
    }
    if (!action && type == (TftpSendRequestsViaIp4 ? IPV4 : IPV6)) //TFTP is agnostic
    {
        action = TftpPollForPacketToSend(type, pData, pDataLength);
        if (action)
        {
            srcPort = TFTP_CLIENT_PORT;
            dstPort = TFTP_SERVER_PORT;
        }
    }
    
    return action;
}
int UdpPollForPacketToSend(int type, int* pSize, char* pPacket)
{
    void* pData    = pPacket + HEADER_LENGTH;
    int dataLength =  *pSize - HEADER_LENGTH;
    
    int action = pollForPacketToSend(type, &dataLength, pData);
    
    *pSize = dataLength + HEADER_LENGTH;
    return action;
}