Rewrite from scratch a TCP/IP stack for mbed. So far the following parts are usable: Drivers: - EMAC driver (from CMSIS 2.0) Protocols: - Ethernet protocol - ARP over ethernet for IPv4 - IPv4 over Ethernet - ICMPv4 over IPv4 - UDPv4 over IPv4 APIs: - Sockets for UDPv4 The structure of this stack is designed to be very modular. Each protocol can register one or more protocol to handle its payload, and in each protocol, an API can be hooked (like Sockets for example). This is an early release.
NetIF.cpp
- Committer:
- Benoit
- Date:
- 2011-06-13
- Revision:
- 5:3cd83fcb1467
- Parent:
- 2:3d1c0fbd10e6
File content as of revision 5:3cd83fcb1467:
/* * $Id: NetIF.c 29 2011-06-11 14:53:08Z benoit $ * $Author: benoit $ * $Date: 2011-06-11 16:53:08 +0200 (sam., 11 juin 2011) $ * $Rev: 29 $ * * * * * */ #include "NetIF.h" #include "Ethernet.h" #include "ARP.h" #include "Debug.h" #include <string.h> #define DEBUG_CURRENT_MODULE_NAME "NetIF" #define DEBUG_CURRENT_MODULE_ID DEBUG_MODULE_NETIF struct PeriodicFunctionTimer { char *name; PeriodicFunction_t function; FunctionPeriod_t period; int32_t age; }; typedef struct PeriodicFunctionTimer PeriodicFunctionTimer_t; static NetIF_t netIF_Table[NETIF_MAX_COUNT]; static int32_t netIF_Count = 0; static RTOS_Mutex_t netIF_TableMutex; static PeriodicFunctionTimer_t netIF_PeriodicFunctionTable[NET_PERIODIC_FUNCTION_MAX_COUNT]; static int32_t netIF_PeriodicFunctionCount = 0; static RTOS_Mutex_t netIF_PeriodicFunctionTableMutex; static Bool_t netIFLayerInitialized = False; static NetPacket_t rxPacket, txPacket; static int32_t gatewayNetIFIndex = -1; static void NetIF_Init(void); mbedNetResult_t mbedNet_LastError; const char *protocol_IDNames[Protocol_ID_Count] = { "Ethernet", "ARP", "IPv4", "ICMPv4", "UDPv4", "TCPv4", }; const char *api_IDNames[API_ID_Count] = { "sockets" }; static void NetIF_Init(void) { mbedNet_LastError = mbedNetResult_Success; DEBUG_MODULE(DEBUG_LEVEL_INFO, ("Initializing NetIF layer")); netIF_Count = 0; memset(netIF_Table, 0, sizeof(netIF_Table)); netIF_TableMutex = RTOS_MUTEX_CREATE(); netIF_PeriodicFunctionCount = 0; memset(netIF_PeriodicFunctionTable, 0, sizeof(netIF_PeriodicFunctionTable)); netIF_PeriodicFunctionTableMutex = RTOS_MUTEX_CREATE(); memset(&rxPacket, 0, sizeof(rxPacket)); memset(&txPacket, 0, sizeof(txPacket)); gatewayNetIFIndex = -1; netIFLayerInitialized = True; } NetIF_t *NetIF_RegisterInterface(IPv4_Addr_t *address, IPv4_Addr_t *netmask, IPv4_Addr_t *gateway, NetIF_Driver_t *driver , void *driverParameter) { NetIF_t *netIF = NULL; if (netIFLayerInitialized == False) { NetIF_Init(); } if (netIF_Count >= NETIF_MAX_COUNT) { DEBUG_SOURCE(DEBUG_LEVEL_ERROR, ("Too many interfaces registered")); mbedNet_LastError = mbedNetResult_TooManyInterfaces; goto Exit; } if (driver == NULL) { DEBUG_SOURCE(DEBUG_LEVEL_ERROR, ("Invalid driver specified")); mbedNet_LastError = mbedNetResult_InvalidDriver; goto Exit; } RTOS_MUTEX_LOCK(netIF_TableMutex); netIF = netIF_Table + netIF_Count; netIF->index = netIF_Count; netIF->name = "en"; netIF->ipv4Address = *address; netIF->ipv4Netmask = *netmask; netIF->ipv4Network.addr = address->addr & netmask->addr; netIF->ipv4Gateway = *gateway; netIF->ipv4Broadcast.addr = (address->addr & netmask->addr) | (~netmask->addr); netIF->driverParameter = driverParameter; netIF->driver = driver; netIF->driver->Init(netIF); netIF->driver->protocolHandler->Init(); if (gateway != NULL) { gatewayNetIFIndex = netIF_Count; } DEBUG_MODULE(DEBUG_LEVEL_INFO, ("Interface '%s%d' registered (%d.%d.%d.%d/%d.%d.%d.%d gw %d.%d.%d.%d) using driver '%s'", netIF->name, netIF_Count, netIF->ipv4Address.IP0, netIF->ipv4Address.IP1, netIF->ipv4Address.IP2, netIF->ipv4Address.IP3, netIF->ipv4Netmask.IP0, netIF->ipv4Netmask.IP1, netIF->ipv4Netmask.IP2, netIF->ipv4Netmask.IP3, netIF->ipv4Gateway.IP0, netIF->ipv4Gateway.IP1, netIF->ipv4Gateway.IP2, netIF->ipv4Gateway.IP3, netIF->driver->name )); netIF_Count++; RTOS_MUTEX_UNLOCK(netIF_TableMutex); Exit: return netIF; } /* int32_t NetIF_ProcessFrames(void) { NetIF_Index_t netIFIndex; NetIF_t *netIF; int32_t result = 0, readResult; DEBUG_SOURCE(DEBUG_LEVEL_VERBOSE2, ("enter")); RTOS_MUTEX_LOCK(netIF_TableMutex); for (netIFIndex = 0; netIFIndex < netIF_Count; netIFIndex++) { netIF = netIF_Table + netIFIndex; readResult = netIF->driver->Read(&rxPacket.data, &rxPacket.length); if (readResult == 0) { rxPacket.depth = -1; netIF->driver->protocolHandler->HandlePacket(netIF, &rxPacket); } } RTOS_MUTEX_UNLOCK(netIF_TableMutex); DEBUG_SOURCE(DEBUG_LEVEL_VERBOSE2, ("leave")); return result; } */ int32_t NetIF_RegisterPeriodicFunction(char *name, PeriodicFunction_t function, FunctionPeriod_t period) { int32_t result = 0; PeriodicFunctionTimer_t *timerEntry; if (netIF_PeriodicFunctionCount >= NET_PERIODIC_FUNCTION_MAX_COUNT) { DEBUG_SOURCE(DEBUG_LEVEL_ERROR, ("Too many periodic functions registered")); mbedNet_LastError = mbedNetResult_TooManyPeriodicFunctions; goto Exit; } RTOS_MUTEX_LOCK(netIF_PeriodicFunctionTableMutex); timerEntry = netIF_PeriodicFunctionTable + netIF_PeriodicFunctionCount; timerEntry->name = name; timerEntry->function = function; timerEntry->period = period; timerEntry->age = 0; DEBUG_MODULE(DEBUG_LEVEL_INFO, ("Registered periodic function '%s' with period %d seconds", name, period )); netIF_PeriodicFunctionCount++; RTOS_MUTEX_UNLOCK(netIF_PeriodicFunctionTableMutex); Exit: return result; } int32_t NetIF_ProcessTimers(int32_t elapsedTime) { int32_t result = 0, timerIndex; PeriodicFunctionTimer_t *timerEntry; static int64_t seconds = 0; seconds++; RTOS_MUTEX_LOCK(netIF_PeriodicFunctionTableMutex); for (timerIndex = 0; timerIndex < netIF_PeriodicFunctionCount; timerIndex++) { timerEntry = netIF_PeriodicFunctionTable + timerIndex; if (elapsedTime == 0) { timerEntry->age = 0; continue; } timerEntry->age += elapsedTime; if (timerEntry->age >= timerEntry->period) { timerEntry->age = 0; timerEntry->function(); } } RTOS_MUTEX_UNLOCK(netIF_PeriodicFunctionTableMutex); return result; } int32_t NetIF_SendIPv4Packet(IPv4_Header_t *ipv4Header) { int32_t result = -1, mtu, lengthToSend; NetIF_Index_t netIFIndex; NetIF_t *netIF = NULL; Ethernet_Header_t *ethernetHeader; Bool_t useGateway = False; RTOS_MUTEX_LOCK(netIF_TableMutex); /* Look for netif having same network */ for (netIFIndex = 0; netIFIndex < netIF_Count; netIFIndex++) { netIF = netIF_Table + netIFIndex; if ( (netIF->up) && ((netIF->ipv4Netmask.addr & ipv4Header->dest.addr) == netIF->ipv4Network.addr)) break; netIF = NULL; } /* if not found, use gateway netif */ if ((netIF == NULL) && (gatewayNetIFIndex >= 0)) { netIF = netIF_Table + gatewayNetIFIndex; if (netIF->up) { DEBUG_MODULE(DEBUG_LEVEL_INFO, ("using gateway %d.%d.%d.%d to talk to %d.%d.%d.%d", netIF->ipv4Gateway.IP0, netIF->ipv4Gateway.IP1, netIF->ipv4Gateway.IP2, netIF->ipv4Gateway.IP3, ipv4Header->dest.IP0, ipv4Header->dest.IP1, ipv4Header->dest.IP2, ipv4Header->dest.IP3 )); useGateway = True; } } /* Still no interface able to send, then return error */ if (netIF == NULL) { DEBUG_MODULE(DEBUG_LEVEL_ERROR, ("No route to host")); mbedNet_LastError = mbedNetResult_NoRouteToHost; goto Exit; } /* Prepare to send the IPv4 packet */ mtu = netIF->driver->mtu; lengthToSend = (sizeof(Ethernet_Header_t) + ntohs(ipv4Header->totalLength)); /* Check that total length doesn't exceed MTU */ if (lengthToSend > mtu) { DEBUG_MODULE(DEBUG_LEVEL_ERROR, ("Too much data: %d bytes", lengthToSend)); mbedNet_LastError = mbedNetResult_TooMuchData; goto Exit; } /* Set source address and compute checksum of IPv4 header */ ipv4Header->source.addr = netIF->ipv4Address.addr; ipv4Header->crc = 0; ipv4Header->crc = IPv4_ComputeCRC(ipv4Header); /* Prepare packet with ethernet data */ txPacket.depth = -1; txPacket.length = lengthToSend; txPacket.data = netIF->driver->GetTxBuffer(); ethernetHeader = (Ethernet_Header_t *)txPacket.data; /* Copy destination MAC address */ if (useGateway) { while (ARP_ResolveIPv4Address(netIF, netIF->ipv4Gateway, ðernetHeader->destination) == -1) { DEBUG_MODULE(DEBUG_LEVEL_VERBOSE0, ("%d.%d.%d.%d not in ARP cache", netIF->ipv4Gateway.IP0, netIF->ipv4Gateway.IP1, netIF->ipv4Gateway.IP2, netIF->ipv4Gateway.IP3 )); } } else { while (ARP_ResolveIPv4Address(netIF, ipv4Header->dest, ðernetHeader->destination) == -1) { DEBUG_MODULE(DEBUG_LEVEL_VERBOSE0, ("%d.%d.%d.%d not in ARP cache", ipv4Header->dest.IP0, ipv4Header->dest.IP1, ipv4Header->dest.IP2, ipv4Header->dest.IP3 )); } } DEBUG_MODULE(DEBUG_LEVEL_VERBOSE0, ("IPv4 sending %d bytes %d.%d.%d.%d --> %d.%d.%d.%d using %s%d", ntohs(ipv4Header->totalLength), ipv4Header->source.IP0, ipv4Header->source.IP1, ipv4Header->source.IP2, ipv4Header->source.IP3, ipv4Header->dest.IP0, ipv4Header->dest.IP1, ipv4Header->dest.IP2, ipv4Header->dest.IP3, netIF->name, netIF->index )); /* Copy source MAC address */ memcpy(ðernetHeader->source, (uint8_t *)netIF->driverParameter, 6); ethernetHeader->protocol = htons(ETHERNET_PROTO_IPV4); NetIF_ProtoPush(&txPacket, sizeof(Ethernet_Header_t), Protocol_ID_Ethernet); /* Copy ethernet payload */ //ipv4Header = (IPv4_Header_t *)txPacket.data; memcpy(txPacket.data, ipv4Header, ntohs(ipv4Header->totalLength)); NetIF_ProtoPop(&txPacket); /* Send packet */ result = netIF->driver->Write(txPacket.data, txPacket.length); Exit: RTOS_MUTEX_UNLOCK(netIF_TableMutex); return result; } int32_t NetIF_Up(NetIF_t *netIF) { int32_t result = 0; if (netIF->up) { result = -1; mbedNet_LastError = mbedNetResult_InterfaceAlreadyUp; goto Exit; } netIF->driver->Enable(); netIF->up = True; Exit: return result; } int32_t NetIF_Down(NetIF_t *netIF) { int32_t result = 0; if (!netIF->up) { result = -1; mbedNet_LastError = mbedNetResult_InterfaceAlreadyDown; goto Exit; } netIF->driver->Disable(); netIF->up = False; Exit: return result; } void NetIF_ProtoPop(NetPacket_t *packet) { static int32_t depth, headerSize, index; DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (">>> Packet depth %d with %d bytes", packet->depth, packet->length)); if (packet->depth >= 0) { depth = packet->depth; headerSize = packet->headerLenTable[depth]; packet->data -= headerSize; packet->length += headerSize; packet->depth--; } DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (" > Decapsulate: ")); DEBUG_BLOCK(DEBUG_LEVEL_VERBOSE1) { for (index = 0; index <= packet->depth; index++) { DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (" > %d %s header:%d bytes", index, protocol_IDNames[packet->protocolTable[index]], packet->headerLenTable[index])); } } DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (">>> Packet depth %d with %d bytes", packet->depth, packet->length)); } void NetIF_ProtoPush(NetPacket_t *packet, int32_t headerSize, Protocol_ID_t protocol) { static int32_t depth, index; DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (">>> Packet depth %d with %d bytes", packet->depth, packet->length)); packet->depth++; depth = packet->depth; packet->headerPtrTable[depth] = packet->data; packet->headerLenTable[depth] = headerSize; packet->protocolTable[depth] = protocol; packet->data += headerSize; packet->length -= headerSize; DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (" > Encapsulate: ")); DEBUG_BLOCK(DEBUG_LEVEL_VERBOSE1) { for (index = 0; index <= depth; index++) { DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (" > %d %s header:%d bytes", index, protocol_IDNames[packet->protocolTable[index]], packet->headerLenTable[index])); } } DEBUG_MODULE(DEBUG_LEVEL_VERBOSE1, (">>> Packet depth %d with %d bytes", packet->depth, packet->length)); }