Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
ip4/ip4.cpp
- Committer:
- andrewboyson
- Date:
- 2017-09-22
- Revision:
- 35:93c39d260a83
- Parent:
- 33:714a0345e59b
- Child:
- 36:900e24b27bfb
File content as of revision 35:93c39d260a83:
#include "mbed.h"
#include "log.h"
#include "net.h"
#include "icmp.h"
#include "udptcp4.h"
#include "ar.h"
#include "nr.h"
#include "dhcp.h"
#include "eth.h"
#include "ip.h"
#include "ip4.h"
#include "ntp.h"
#define DEBUG false
#define IP4_BROADCAST_ADDRESS 0xFFFFFFFF
#define IP4_MULTICAST_ALL_HOSTS 0x010000E0
#define IP4_MULTICAST_ALL_ROUTERS 0x020000E0
#define IP4_MULTICAST_DNS_ADDRESS 0xFB0000E0
#define IP4_MULTICAST_LLMNR_ADDRESS 0xFC0000E0
int Ip4AddressToString(uint32_t ip, int size, char* text)
{
int a0 = (ip & 0xFF000000) >> 24;
int a1 = (ip & 0x00FF0000) >> 16;
int a2 = (ip & 0x0000FF00) >> 8;
int a3 = (ip & 0x000000FF);
return snprintf(text, size, "%d.%d.%d.%d", a3, a2, a1, a0);
}
uint32_t Ip4Parse(char* text)
{
int ints[4];
sscanf(text, "%d.%d.%d.%d", &ints[3], &ints[2], &ints[1], &ints[0]);
return (ints[0] << 24) + (ints[1] << 16) + (ints[2] << 8) + ints[3];
}
void Ip4DestIpFromAction(int action, uint32_t* pDstIp)
{
switch (action)
{
case UNICAST: break;
case UNICAST_DNS: *pDstIp = DhcpDnsServer; break;
case UNICAST_DHCP: *pDstIp = DhcpServer; break;
case UNICAST_NTP: *pDstIp = NtpServerIp4; break;
case MULTICAST_NODE: *pDstIp = IP4_MULTICAST_ALL_HOSTS; break;
case MULTICAST_ROUTER: *pDstIp = IP4_MULTICAST_ALL_ROUTERS; break;
case MULTICAST_MDNS: *pDstIp = IP4_MULTICAST_DNS_ADDRESS; break;
case MULTICAST_LLMNR: *pDstIp = IP4_MULTICAST_LLMNR_ADDRESS; break;
case BROADCAST: *pDstIp = IP4_BROADCAST_ADDRESS; break;
default:
LogTimeF("Ip4 DestIpFromAction unknown action %d\r\n", action);
break;
}
}
#define HEADER_LENGTH 20
__packed struct header
{
uint8_t versionIhl;
uint8_t tos;
uint16_t length;
uint16_t id;
uint16_t flagsOffset;
uint8_t ttl;
uint8_t protocol;
uint16_t checksum;
uint32_t src;
uint32_t dst;
};
//Header variables
static uint8_t version;
static int headerLength;
static uint8_t tos;
static uint16_t id;
static bool dontFragment;
static bool moreFragments;
static uint16_t offset;
static uint8_t ttl;
static uint8_t protocol;
static uint16_t checksum;
static uint16_t calcsum;
static uint32_t srcIp;
static uint32_t dstIp;
static void* pData;
static int dataLength;
void Ip4LogHeaderSrc()
{
char text[64];
Ip4AddressToString(srcIp, sizeof(text), text);
Log(text);
}
void Ip4LogHeaderDst()
{
char text[64];
Ip4AddressToString(dstIp, sizeof(text), text);
Log(text);
}
void readHeader(struct header * pHeader)
{
version = pHeader->versionIhl >> 4;
uint8_t ihl = pHeader->versionIhl & 0xF;
headerLength = ihl * 4;
tos = pHeader->tos;
uint16_t totalLength = NetToHost16(pHeader->length);
id = NetToHost16(pHeader->id);
uint16_t flagsOffset = NetToHost16(pHeader->flagsOffset);
dontFragment = flagsOffset & 0x4000;
moreFragments = flagsOffset & 0x8000;
offset = flagsOffset & 0x1FFF;
ttl = pHeader->ttl;
protocol = pHeader->protocol;
checksum = NetToHost16(pHeader->checksum);
calcsum = NetCheckSum(headerLength, pHeader);
srcIp = pHeader->src;
dstIp = pHeader->dst;
pData = (char*)pHeader + headerLength;
dataLength = totalLength - headerLength;
}
void writeHeader(struct header * pHeader)
{
uint16_t flagsOffset = offset;
if (dontFragment) flagsOffset |= 0x4000;
if (moreFragments) flagsOffset |= 0x8000;
uint8_t ihl = headerLength >> 2;
pHeader->versionIhl = (version << 4) + ihl;
pHeader->tos = tos;
pHeader->id = NetToHost16(id);
pHeader->flagsOffset = NetToHost16(flagsOffset);
pHeader->ttl = ttl;
pHeader->protocol = protocol;
pHeader->dst = dstIp;
pHeader->src = srcIp;
pHeader->length = NetToHost16(headerLength + dataLength);
pHeader->checksum = 0;
pHeader->checksum = NetCheckSum(headerLength, pHeader);
calcsum = 0;
}
static void logHeader(char* title)
{
char text[30];
LogTimeF("%s\r\n", title);
LogF(" Version %d\r\n", version);
LogF(" Header length %d\r\n", headerLength);
LogF(" Type of service %d\r\n", tos);
LogF(" Data length %d\r\n", dataLength);
LogF(" Identification %d\r\n", id);
if (dontFragment) LogF(" Don't fragment\r\n");
else LogF(" Do fragment\r\n");
if (moreFragments) LogF(" More fragments\r\n");
else LogF(" No more fragments\r\n");
LogF(" Offset %d\r\n", offset);
LogF(" Time to live %d\r\n", ttl);
IpProtocolToString(protocol, sizeof(text), text);
LogF(" Protocol %s\r\n", text);
LogF(" Checksum (hex) %04hX\r\n", checksum);
LogF(" Calculated (hex) %04hX\r\n", calcsum);
Ip4AddressToString(srcIp, sizeof(text), text);
LogF(" Source IP %s\r\n", text);
Ip4AddressToString(dstIp, sizeof(text), text);
LogF(" Destination IP %s\r\n", text);
}
int Ip4HandleReceivedPacket(char* pSrcMac, void* pPacket, int* pSize, char* pDstMac)
{
struct header * pHeader = (header*)pPacket;
readHeader(pHeader);
bool isMe = dstIp == DhcpLocalIp;
bool isLocalBroadcast = dstIp == DhcpLocalIp | 0xFF000000;
bool isBroadcast = dstIp == IP4_BROADCAST_ADDRESS;
bool isMulticast = (dstIp & 0xE0) == 0xE0; //224.x.x.x == 1110 0000 == E0.xx.xx.xx == xx.xx.xx.E0 in little endian
bool doIt = isMe || isLocalBroadcast || isBroadcast || isMulticast;
if (!doIt)
{
if (DEBUG)
{
char text[20];
Ip4AddressToString(dstIp, sizeof(text), text);
LogTimeF("IP4 filtered out ip %s ", text);
Ip4AddressToString(srcIp, sizeof(text), text);
LogF("from %s \r\n", text);
}
return DO_NOTHING;
}
ArAddIp4Record(pSrcMac, srcIp);
NrMakeRequestForNameFromIp4(srcIp);
if (DEBUG) logHeader("IP4 packet received");
int action = DO_NOTHING;
switch (protocol)
{
case ICMP: action = IcmpHandleReceivedPacket(&srcIp, &dstIp, &dataLength, pData); break;
case IGMP: return DO_NOTHING;
case UDP: action = Udp4HandleReceivedPacket(&srcIp, &dstIp, &dataLength, pData); break;
case TCP: action = Tcp4HandleReceivedPacket(&srcIp, &dstIp, &dataLength, pData); break;
case IP6IN4: return DO_NOTHING;
default:
logHeader("IP4 packet unhandled");
return DO_NOTHING;
}
if (!action) return DO_NOTHING;
memcpy(pDstMac, pSrcMac, 6);
if (DEBUG) logHeader("IP4 packet replied to");
writeHeader(pHeader);
*pSize = headerLength + dataLength;
return action;
}
int Ip4PollForPacketToSend(void* pPacket, int* pSize, char* pDstMac)
{
headerLength = HEADER_LENGTH;
pData = (char*)pPacket + headerLength;
dataLength = 0;
version = 4;
tos = 0;
id = 0;
dontFragment = true;
moreFragments = false;
offset = 0;
ttl = 255;
protocol = UDP;
int action = DO_NOTHING;
if (!action) action = Udp4PollForPacketToSend(pData, &dataLength, &srcIp, &dstIp);
if (!action) return DO_NOTHING;
switch (action)
{
case UNICAST:
case UNICAST_DNS:
case UNICAST_DHCP:
case UNICAST_NTP:
ArIpToMac4(dstIp, pDstMac); //Make the remote MAC from ARP
break;
case BROADCAST:
break;
default:
LogTimeF("Ip4PollForPacketToSend - undefined action %d\r\n", action);
break;
}
if (DEBUG) logHeader("IP4 polled packet sent");
writeHeader((header*)pPacket);
*pSize = headerLength + dataLength;
return action;
}