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-05-09
- Revision:
- 15:6ca6778168b1
- Parent:
- 14:e75a59c1123d
- Child:
- 18:accfcb80d9c3
File content as of revision 15:6ca6778168b1:
#include "mbed.h" #include "log.h" #include "net.h" #include "icmp.h" #include "udptcp4.h" #include "ar.h" #include "dhcp.h" #include "eth.h" #include "ip.h" #include "ip4.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); } 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 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; uint32_t Ip4Src; uint32_t Ip4Dst; 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); Ip4Src = pHeader->src; Ip4Dst = 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 = Ip4Dst; pHeader->src = Ip4Src; 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(Ip4Src, sizeof(text), text); LogF(" Source IP %s\r\n", text); Ip4AddressToString(Ip4Dst, 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 = Ip4Dst == DhcpLocalIp; bool isLocalBroadcast = Ip4Dst == DhcpLocalIp | 0xFF000000; bool isBroadcast = Ip4Dst == IP4_BROADCAST_ADDRESS; bool isMulticast = (Ip4Dst & 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(Ip4Dst, sizeof(text), text); LogTimeF("IP4 filtered out ip %s ", text); Ip4AddressToString(Ip4Src, sizeof(text), text); LogF("from %s \r\n", text); } return DO_NOTHING; } ArAdd4(pSrcMac, Ip4Src); if (DEBUG) logHeader("IP4 packet received"); int action = DO_NOTHING; switch (protocol) { case ICMP: action = IcmpHandleReceivedPacket(&Ip4Src, &Ip4Dst, &dataLength, pData); break; case IGMP: return DO_NOTHING; case UDP: action = Udp4HandleReceivedPacket(&Ip4Src, &Ip4Dst, &dataLength, pData); break; case TCP: action = Tcp4HandleReceivedPacket(&Ip4Src, &Ip4Dst, &dataLength, pData); break; 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, &Ip4Src, &Ip4Dst); if (!action) return DO_NOTHING; switch (action) { case UNICAST: case UNICAST_DNS: case UNICAST_DHCP: ArRev4(Ip4Dst, pDstMac); //Make the remote MAC from ARP break; } if (DEBUG) logHeader("IP4 polled packet sent"); writeHeader((header*)pPacket); *pSize = headerLength + dataLength; return action; }