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
ip4/ip4.cpp
- Committer:
- andrewboyson
- Date:
- 2017-10-22
- Revision:
- 44:83ce5ace337b
- Parent:
- 43:bc028d5a6424
- Child:
- 47:73af5c0b0dc2
File content as of revision 44:83ce5ace337b:
#include "mbed.h" #include "log.h" #include "net.h" #include "action.h" #include "icmp4.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" #include "mac.h" #define SHOW_FILTERED true #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 Ip4DestIpFromDest(int dest, uint32_t* pDstIp) { switch (dest) { 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("Ip4DestIpFromDest unknown destination %d\r\n", dest); 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 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 text[30]; if (NetTraceVerbose) { Log ("IP4 header\r\n"); 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); } else { Log ("IP4 header "); IpProtocolToString(protocol, sizeof(text), text); Log(text); Log(" "); Ip4AddressToString(srcIp, sizeof(text), text); Log(text); Log(" >>> "); Ip4AddressToString(dstIp, sizeof(text), text); Log(text); Log("\r\n"); } } static void (*pTraceBack)(void); static void trace() { pTraceBack(); logHeader(); } int Ip4HandleReceivedPacket(void (*traceback)(void), char* pSrcMac, void* pPacket, int* pSize, char* pDstMac) { pTraceBack = traceback; 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 (SHOW_FILTERED) { 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); int action = DO_NOTHING; switch (protocol) { case ICMP: action = Icmp4HandleReceivedPacket(trace, &srcIp, &dstIp, &dataLength, pData); break; case IGMP: break; case UDP: action = Udp4HandleReceivedPacket(trace, &srcIp, &dstIp, &dataLength, pData); break; case TCP: action = Tcp4HandleReceivedPacket(trace, &srcIp, &dstIp, &dataLength, pData); break; case IP6IN4: break; default: LogTimeF("IP4 received packet unknown protocol %d\r\n"); return DO_NOTHING; } if (!action) return DO_NOTHING; if (DhcpIpNeedsToBeRouted(dstIp)) ArIpToMac4(DhcpRouter, pDstMac); //Send back to the router else MacCopy(pDstMac, pSrcMac); //Send back to the source writeHeader(pHeader); *pSize = headerLength + dataLength; if (ActionGetTracePart(action)) logHeader(); 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; int dest = ActionGetDestPart(action); switch (dest) { case UNICAST: case UNICAST_DNS: case UNICAST_DHCP: case UNICAST_NTP: if (DhcpIpNeedsToBeRouted(dstIp)) ArIpToMac4(DhcpRouter, pDstMac); //send via router else ArIpToMac4(dstIp, pDstMac); //Send direct break; case MULTICAST_NODE: case MULTICAST_ROUTER: case MULTICAST_MDNS: case MULTICAST_LLMNR: case BROADCAST: break; default: LogTimeF("Ip4PollForPacketToSend - undefined destination %d\r\n", dest); break; } writeHeader((header*)pPacket); *pSize = headerLength + dataLength; if (ActionGetTracePart(action)) logHeader(); return action; }