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-26
Revision:
7:8e12f7357b9f
Parent:
5:3cd83fcb1467

File content as of revision 7:8e12f7357b9f:

/*
 * $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, &ethernetHeader->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, &ethernetHeader->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(&ethernetHeader->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));
}