OpenCores
URL https://opencores.org/ocsvn/mlite/mlite/trunk

Subversion Repositories mlite

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 154 to Rev 155
    Reverse comparison

Rev 154 → Rev 155

/trunk/kernel/http.c
0,0 → 1,174
/*--------------------------------------------------------------------
* TITLE: Plasma TCP/IP HTTP Server
* AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
* DATE CREATED: 4/22/06
* FILENAME: http.c
* PROJECT: Plasma CPU core
* COPYRIGHT: Software placed into the public domain by the author.
* Software 'as is' without warranty. Author liable for nothing.
* DESCRIPTION:
* Plasma TCP/IP HTTP Server
*--------------------------------------------------------------------*/
#ifdef WIN32
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define _LIBC
#endif
#include "rtos.h"
#include "tcpip.h"
#ifdef WIN32
#define UartPrintf printf
#endif
 
const char pageGif[]=
{
"HTTP/1.0 200 OK\r\n"
"Content-Type: binary/gif\r\n\r\n"
};
const char pageBinary[]=
{
"HTTP/1.0 200 OK\r\n"
"Content-Type: binary/binary\r\n\r\n"
};
const char pageHtml[]={
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
};
const char pageText[]={
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/text\r\n\r\n"
};
const char pageEmpty[]=
{
"HTTP/1.0 404 OK\r\n"
"Content-Type: text/html\r\n\r\n"
};
 
static const PageEntry_t *HtmlPages;
static int HtmlFiles;
 
 
void HttpServer(IPSocket *socket)
{
uint8 buf[600];
int bytes, i, length, len, needFooter;
char *name=NULL, *page=NULL;
 
if(socket == NULL)
return;
bytes = IPRead(socket, buf, sizeof(buf)-1);
if(bytes)
{
buf[bytes] = 0;
if(strncmp((char*)buf, "GET /", 5) == 0)
{
for(i = 0; ; ++i)
{
length = HtmlPages[i].length;
if(length == -1)
break;
name = (char*)HtmlPages[i].name;
page = (char*)HtmlPages[i].page;
len = (int)strlen(name);
if(strncmp((char*)buf+4, name, len) == 0)
break;
}
#ifdef WIN32
if(length == -1 && HtmlFiles)
{
FILE *file;
char *ptr;
 
name = (char*)buf + 5;
ptr = strstr(name, " ");
if(ptr)
*ptr = 0;
file = fopen(name, "rb");
if(file)
{
page = (char*)malloc(1024*1024*8);
length = (int)fread(page, 1, 1024*1024*8, file);
fclose(file);
}
}
#endif
if(length != -1)
{
if(length == -2)
{
IPFuncPtr funcPtr = (IPFuncPtr)page;
funcPtr(socket, buf);
return;
}
if(length == 0)
length = (int)strlen(page);
needFooter = 0;
if(strstr(name, ".html"))
IPWrite(socket, (uint8*)pageHtml, (int)strlen(pageHtml));
else if(strstr(name, ".htm") || strcmp(name, "/ ") == 0)
{
IPWrite(socket, (uint8*)HtmlPages[0].page, (int)strlen(HtmlPages[0].page));
needFooter = 1;
}
else if(strstr(HtmlPages[i].name, ".gif"))
IPWrite(socket, (uint8*)pageGif, (int)strlen(pageGif));
else
IPWrite(socket, (uint8*)pageBinary, (int)strlen(pageBinary));
IPWrite(socket, (uint8*)page, length);
if(needFooter)
IPWrite(socket, (uint8*)HtmlPages[1].page, (int)strlen(HtmlPages[1].page));
#ifdef WIN32
if(page != HtmlPages[i].page)
free(page);
#endif
}
else
{
IPWrite(socket, (uint8*)pageEmpty, (int)strlen(pageEmpty));
}
IPClose(socket);
}
}
}
 
 
void HttpInit(const PageEntry_t *Pages, int UseFiles)
{
HtmlPages = Pages;
HtmlFiles = UseFiles;
IPOpen(IP_MODE_TCP, 0, 80, HttpServer);
IPOpen(IP_MODE_TCP, 0, 8080, HttpServer);
}
 
 
#if 0
//Example test code
static void MyProg(IPSocket *socket, char *request)
{
char *text="HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
"<html><body>Hello World!</body></html>";
(void)request;
IPWrite(socket, text, (int)strlen(text));
IPClose(socket);
}
static const PageEntry_t pageEntry[]=
{ //name, length, htmlText
{"/Header", 0, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
"<HTML><HEAD><TITLE>Plasma CPU</TITLE></HEAD>\n<BODY>"},
{"/Footer", 0, "</BODY></HTML>"},
{"/ ", 0, "<h2>Home Page</h2>Welcome! <a href='/other.htm'>Other</a>"
" <a href='/cgi/myprog'>myprog</a>"},
{"/other.htm ", 0, "<h2>Other</h2>Other."},
//{"/binary/plasma.gif ", 1945, PlasmaGif},
{"/cgi/myprog", HTML_LENGTH_CALLBACK, (char*)MyProg},
{"", HTML_LENGTH_LIST_END, NULL}
};
void HttpTest(void)
{
HttpInit(pageEntry, 0);
}
#endif
 
 
/trunk/kernel/tcpip.c
0,0 → 1,1449
/*--------------------------------------------------------------------
* TITLE: Plasma TCP/IP Protocol Stack
* AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
* DATE CREATED: 4/22/06
* FILENAME: tcpip.c
* PROJECT: Plasma CPU core
* COPYRIGHT: Software placed into the public domain by the author.
* Software 'as is' without warranty. Author liable for nothing.
* DESCRIPTION:
* Plasma TCP/IP Protocol Stack
*
* Possible call stack when receiving a packet:
* IPMainThread()
* IPProcessEthernetPacket()
* IPProcessTCPPacket()
* TCPSendPacket()
* IPSendPacket()
* IPChecksum()
* IPSendFrame()
* FrameInsert()
*--------------------------------------------------------------------*/
#ifdef WIN32
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define _LIBC
#endif
#include "rtos.h"
#include "tcpip.h"
 
#ifdef WIN32
#undef OS_CriticalBegin
#undef OS_CriticalEnd
#define OS_CriticalBegin() 0
#define OS_CriticalEnd(A)
#define OS_ThreadCreate(A,B,C,D,E) 0
#define OS_ThreadSleep(A)
#define OS_ThreadTime() 0
#define OS_SemaphoreCreate(A,B) NULL
#define OS_SemaphorePend(A,B) 0
#define OS_SemaphorePost(A)
#define OS_MQueueCreate(A,B,C) 0
#define OS_MQueueSend(A,B) 0
#define OS_MQueueGet(A,B,C) 0
#define UartPacketConfig(A,B,C)
#define UartPacketSend(A,B)
#define UartPrintf printf
#define UartPrintfCritical printf
#define Led(A)
#endif
 
//ETHER FIELD OFFSET LENGTH VALUE
#define ETHERNET_DEST 0 //6
#define ETHERNET_SOURCE 6 //6
#define ETHERNET_FRAME_TYPE 12 //2 IP=0x0800; ARP=0x0806
 
//ARP FIELD OFFSET LENGTH VALUE
#define ARP_HARD_TYPE 14 //2 0x0001
#define ARP_PROT_TYPE 16 //2 0x0800
#define ARP_HARD_SIZE 18 //1 0x06
#define ARP_PROT_SIZE 19 //1 0x04
#define ARP_OP 20 //2 ARP=1;ARPreply=2
#define ARP_ETHERNET_SENDER 22 //6
#define ARP_IP_SENDER 28 //4
#define ARP_ETHERNET_TARGET 32 //6
#define ARP_IP_TARGET 38 //4
#define ARP_PAD 42 //18 0
 
//IP FIELD OFFSET LENGTH VALUE
#define IP_VERSION_LENGTH 14 //1 0x45
#define IP_TYPE_OF_SERVICE 15 //1 0x00
#define IP_LENGTH 16 //2
#define IP_ID16 18 //2
#define IP_FRAG_OFFSET 20 //2
#define IP_TIME_TO_LIVE 22 //1 0x80
#define IP_PROTOCOL 23 //1 TCP=0x06;PING=0x01;UDP=0x11
#define IP_CHECKSUM 24 //2
#define IP_SOURCE 26 //4
#define IP_DEST 30 //4
 
//PSEUDO FIELD OFFSET LENGTH VALUE
#define PSEUDO_IP_SOURCE 0 //4
#define PSEUDO_IP_DEST 4 //4
#define PSEUDO_ZERO 8 //1 0
#define PSEUDO_IP_PROTOCOL 9 //1
#define PSEUDO_LENGTH 10 //2
 
//UDP FIELD OFFSET LENGTH VALUE
#define UDP_SOURCE_PORT 34 //2
#define UDP_DEST_PORT 36 //2
#define UDP_LENGTH 38 //2
#define UDP_CHECKSUM 40 //2
#define UDP_DATA 42
 
//DHCP FIELD OFFSET LENGTH VALUE
#define DHCP_OPCODE 42 //1 REQUEST=1;REPLY=2
#define DHCP_HW_TYPE 43 //1 1
#define DHCP_HW_LEN 44 //1 6
#define DHCP_HOP_COUNT 45 //1 0
#define DHCP_TRANS_ID 46 //4
#define DHCP_NUM_SEC 50 //2 0
#define DHCP_UNUSED 52 //2
#define DHCP_CLIENT_IP 54 //4
#define DHCP_YOUR_IP 58 //4
#define DHCP_SERVER_IP 62 //4
#define DHCP_GATEWAY_IP 66 //4
#define DHCP_CLIENT_ETHERNET 70 //16
#define DHCP_SERVER_NAME 86 //64
#define DHCP_BOOT_FILENAME 150 //128
#define DHCP_MAGIC_COOKIE 278 //4 0x63825363
#define DHCP_OPTIONS 282 //N
 
#define DHCP_MESSAGE_TYPE 53 //1 type
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_ACK 5
#define DHCP_REQUEST_IP 50 //4 ip
#define DHCP_REQUEST_SERV_IP 54 //4 ip
#define DHCP_CLIENT_ID 61 //7 1 ethernet
#define DHCP_HOST_NAME 12 //6 plasma
#define DHCP_PARAMS 55 //4 1=subnet; 15=domain_name; 3=router; 6=dns
#define DHCP_PARAM_SUBNET 1
#define DHCP_PARAM_ROUTER 3
#define DHCP_PARAM_DNS 6
#define DHCP_END_OPTION 0xff
 
//DHCP FIELD OFFSET LENGTH VALUE
#define DNS_ID 0 //2
#define DNS_FLAGS 2 //2
#define DNS_NUM_QUESTIONS 4 //2 1
#define DNS_NUM_ANSWERS_RR 6 //2 0/1
#define DNS_NUM_AUTHORITY_RR 8 //2 0
#define DNS_NUM_ADDITIONAL_RR 10 //2 0
#define DNS_QUESTIONS 12 //2
 
#define DNS_FLAGS_RESPONSE 0x8000
#define DNS_FLAGS_RECURSIVE 0x0100
#define DNS_FLAGS_ERROR 0x0003
#define DNS_FLAGS_OK 0x0000
#define DNS_QUERY_TYPE_IP 1
#define DNS_QUERY_CLASS 1
#define DNS_PORT 53
 
//TCP FIELD OFFSET LENGTH VALUE
#define TCP_SOURCE_PORT 34 //2
#define TCP_DEST_PORT 36 //2
#define TCP_SEQ 38 //4
#define TCP_ACK 42 //4
#define TCP_HEADER_LENGTH 46 //1 0x50
#define TCP_FLAGS 47 //1 SYNC=0x2;ACK=0x10;FIN=0x1
#define TCP_WINDOW_SIZE 48 //2
#define TCP_CHECKSUM 50 //2
#define TCP_URGENT_POINTER 52 //2
#define TCP_DATA 54 //length-N
 
#define TCP_FLAGS_FIN 1
#define TCP_FLAGS_SYN 2
#define TCP_FLAGS_RST 4
#define TCP_FLAGS_ACK 16
 
//PING FIELD OFFSET LENGTH VALUE
#define PING_TYPE 34 //1 SEND=8;REPLY=0
#define PING_CODE 35 //1 0
#define PING_CHECKSUM 36 //2
#define PING_ID 38 //2
#define PING_SEQUENCE 40 //2
#define PING_DATA 44
 
static void IPClose2(IPSocket *Socket);
 
static uint8 ethernetAddressNull[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4};
static uint8 ethernetAddressGateway[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
static uint8 ipAddressPlasma[] = {0x9d, 0xfe, 0x28, 10}; //changed by DHCP
static uint8 ipAddressGateway[] = {0xff, 0xff, 0xff, 0xff}; //changed by DHCP
static uint32 ipAddressDns; //changed by DHCP
 
static OS_Semaphore_t *IPSemaphore;
static OS_Semaphore_t *FrameGetSem;
static int FrameFreeCount=FRAME_COUNT;
static int FrameWaitCount;
static IPFrame *FrameFreeHead;
static IPFrame *FrameSendHead;
static IPFrame *FrameSendTail;
static IPFrame *FrameResendHead;
static IPFrame *FrameResendTail;
static IPSocket *SocketHead;
static uint32 Seconds;
static int DhcpRetrySeconds;
static IPFuncPtr FrameSendFunc;
static OS_MQueue_t *IPMQueue;
int IPVerbose=1;
 
static const unsigned char dhcpDiscover[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dest
0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //src
0x08, 0x00,
0x45, 0x00, 0x01, 0x48, 0x2e, 0xf5, 0x00, 0x00, //ip
0x80, 0x11, 0x0a, 0xb1, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff,
0x00, 0x44, 0x00, 0x43, 0x01, 0x34, 0x45, 0x66, //udp
0x01, 0x01, 0x06, 0x00, 0x69, 0x26, 0xb5, 0x52 //dhcp
};
 
static const unsigned char dhcpOptions[] = {
0x63, 0x82, 0x53, 0x63, //cookie
0x35, 0x01, 0x01, //DHCP Discover
0x3d, 0x07, 0x01, 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //Client identifier
0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'a', //Host name
0x37, 0x03, DHCP_PARAM_SUBNET, DHCP_PARAM_ROUTER, DHCP_PARAM_DNS, //Parameters
DHCP_END_OPTION
};
 
 
//Get a free frame; can be called from an ISR
IPFrame *IPFrameGet(int freeCount, int pend)
{
IPFrame *frame=NULL;
uint32 state;
for(;;)
{
state = OS_CriticalBegin();
if(FrameFreeCount >= freeCount)
{
--FrameFreeCount;
frame = FrameFreeHead;
if(FrameFreeHead)
FrameFreeHead = FrameFreeHead->next;
}
else if(frame == NULL && pend && FrameSendFunc == NULL)
++FrameWaitCount;
OS_CriticalEnd(state);
if(frame == NULL && pend && FrameSendFunc == NULL)
{
OS_SemaphorePend(FrameGetSem, 10);
continue;
}
break;
}
if(frame)
{
assert(frame->state == 0);
frame->state = 1;
}
else if(IPVerbose)
UartPrintfCritical(":");
return frame;
}
 
 
static void FrameFree(IPFrame *frame)
{
uint32 state;
int needPost=0;
 
assert(frame->state == 1);
frame->state = 0;
state = OS_CriticalBegin();
frame->next = FrameFreeHead;
FrameFreeHead = frame;
++FrameFreeCount;
if(FrameWaitCount)
{
--FrameWaitCount;
needPost = 1;
}
OS_CriticalEnd(state);
if(needPost)
OS_SemaphorePost(FrameGetSem);
}
 
 
static void FrameInsert(IPFrame **head, IPFrame **tail, IPFrame *frame)
{
assert(frame->state == 1);
frame->state = 2;
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
frame->prev = NULL;
frame->next = *head;
if(*head)
(*head)->prev = frame;
*head = frame;
if(*tail == NULL)
*tail = frame;
OS_SemaphorePost(IPSemaphore);
}
 
 
static void FrameRemove(IPFrame **head, IPFrame **tail, IPFrame *frame)
{
assert(frame->state == 2);
frame->state = 1;
if(frame->prev)
frame->prev->next = frame->next;
else
*head = frame->next;
if(frame->next)
frame->next->prev = frame->prev;
else
*tail = frame->prev;
frame->prev = NULL;
frame->next = NULL;
}
 
 
static int IPChecksum(int checksum, const unsigned char *data, int length)
{
int i;
checksum = ~checksum & 0xffff;
for(i = 0; i < length-1; i += 2)
{
checksum += (data[i] << 8) | data[i+1];
}
if(i < length)
checksum += data[i] << 8;
while(checksum >> 16)
checksum = (checksum & 0xffff) + (checksum >> 16);
checksum = ~checksum & 0xffff;
return checksum;
}
 
 
static int EthernetVerifyChecksums(const unsigned char *packet, int length)
{
int checksum, length2;
unsigned char pseudo[12];
 
//Calculate checksums
if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP
{
checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20);
if(checksum)
return -1;
if(packet[IP_PROTOCOL] == 0x01) //PING
{
checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE);
}
else if(packet[IP_PROTOCOL] == 0x11) //UDP
{
if(packet[UDP_CHECKSUM] == 0 && packet[UDP_CHECKSUM+1] == 0)
return 0;
memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
pseudo[PSEUDO_ZERO] = 0;
pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2);
checksum = IPChecksum(0xffff, pseudo, 12);
length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1];
checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length);
}
else if(packet[IP_PROTOCOL] == 0x06) //TCP
{
memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
pseudo[PSEUDO_ZERO] = 0;
pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
length = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1];
length2 = length - 20;
pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8);
pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2;
checksum = IPChecksum(0xffff, pseudo, 12);
checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2);
}
if(checksum)
return -1;
}
return 0;
}
 
 
static void IPFrameReschedule(IPFrame *frame)
{
int length;
length = frame->length - TCP_DATA;
if(frame->packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_ACK))
++length;
if(frame->socket == NULL || frame->socket->state == IP_UDP || length == 0 ||
++frame->retryCnt > 4)
{
FrameFree(frame); //can't be ACK'ed
}
else
{
//Put on resend list until TCP ACK'ed
frame->timeout = RETRANSMIT_TIME;
FrameInsert(&FrameResendHead, &FrameResendTail, frame);
}
}
 
 
static void IPSendFrame(IPFrame *frame)
{
uint32 message[4];
 
if(FrameSendFunc)
{
//Single threaded
FrameSendFunc(frame->packet, frame->length);
IPFrameReschedule(frame);
}
else
{
//Add Packet to send queue
FrameInsert(&FrameSendHead, &FrameSendTail, frame);
 
//Wakeup sender thread
message[0] = 2;
OS_MQueueSend(IPMQueue, message);
}
}
 
 
static void IPSendPacket(IPSocket *socket, IPFrame *frame, int length)
{
int checksum, length2=length;
unsigned char pseudo[12], *packet=frame->packet;
 
frame->length = (uint16)length;
 
//Calculate checksums
if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP
{
length2 = length - IP_VERSION_LENGTH;
packet[IP_LENGTH] = (uint8)(length2 >> 8);
packet[IP_LENGTH+1] = (uint8)length2;
memset(packet+IP_CHECKSUM, 0, 2);
checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20);
packet[IP_CHECKSUM] = (unsigned char)(checksum >> 8);
packet[IP_CHECKSUM+1] = (unsigned char)checksum;
if(packet[IP_PROTOCOL] == 0x01) //PING
{
memset(packet+PING_CHECKSUM, 0, 2);
checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE);
packet[PING_CHECKSUM] = (unsigned char)(checksum >> 8);
packet[PING_CHECKSUM+1] = (unsigned char)checksum;
}
else if(packet[IP_PROTOCOL] == 0x11) //UDP
{
length2 = length - UDP_SOURCE_PORT;
packet[UDP_LENGTH] = (uint8)(length2 >> 8);
packet[UDP_LENGTH+1] = (uint8)length2;
memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
pseudo[PSEUDO_ZERO] = 0;
pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2);
checksum = IPChecksum(0xffff, pseudo, 12);
memset(packet+UDP_CHECKSUM, 0, 2);
length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1];
checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length2);
packet[UDP_CHECKSUM] = (unsigned char)(checksum >> 8);
packet[UDP_CHECKSUM+1] = (unsigned char)checksum;
}
else if(packet[IP_PROTOCOL] == 0x06) //TCP
{
memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
pseudo[PSEUDO_ZERO] = 0;
pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
length2 = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1];
length2 = length2 - 20;
pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8);
pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2;
checksum = IPChecksum(0xffff, pseudo, 12);
memset(packet+TCP_CHECKSUM, 0, 2);
checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2);
packet[TCP_CHECKSUM] = (unsigned char)(checksum >> 8);
packet[TCP_CHECKSUM+1] = (unsigned char)checksum;
}
}
 
if(socket && (packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_ACK)))
length2 = 1;
frame->socket = socket;
frame->timeout = 0;
frame->retryCnt = 0;
if(socket)
frame->seqEnd = socket->seq + length2;
IPSendFrame(frame);
}
 
 
static void TCPSendPacket(IPSocket *socket, IPFrame *frame, int length)
{
uint8 *packet = frame->packet;
int flags;
 
flags = packet[TCP_FLAGS];
memcpy(packet, socket->headerSend, TCP_SEQ);
packet[TCP_FLAGS] = (uint8)flags;
if(flags & TCP_FLAGS_SYN)
packet[TCP_HEADER_LENGTH] = 0x60; //set maximum segment size
else
packet[TCP_HEADER_LENGTH] = 0x50;
packet[TCP_SEQ] = (uint8)(socket->seq >> 24);
packet[TCP_SEQ+1] = (uint8)(socket->seq >> 16);
packet[TCP_SEQ+2] = (uint8)(socket->seq >> 8);
packet[TCP_SEQ+3] = (uint8)socket->seq;
packet[TCP_ACK] = (uint8)(socket->ack >> 24);
packet[TCP_ACK+1] = (uint8)(socket->ack >> 16);
packet[TCP_ACK+2] = (uint8)(socket->ack >> 8);
packet[TCP_ACK+3] = (uint8)socket->ack;
packet[TCP_WINDOW_SIZE] = 128;
packet[TCP_WINDOW_SIZE+1] = 0;
packet[TCP_URGENT_POINTER] = 0;
packet[TCP_URGENT_POINTER+1] = 0;
IPSendPacket(socket, frame, length);
}
 
 
static void EthernetCreateResponse(unsigned char *packetOut,
const unsigned char *packet,
int length)
{
//Swap destination and source fields
memcpy(packetOut, packet, length);
memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6);
memcpy(packetOut+ETHERNET_SOURCE, packet+ETHERNET_DEST, 6);
if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP
{
memcpy(packetOut+IP_SOURCE, packet+IP_DEST, 4);
memcpy(packetOut+IP_DEST, packet+IP_SOURCE, 4);
if(packet[IP_PROTOCOL] == 0x06 || packet[IP_PROTOCOL] == 0x11) //TCP/UDP
{
memcpy(packetOut+TCP_SOURCE_PORT, packet+TCP_DEST_PORT, 2);
memcpy(packetOut+TCP_DEST_PORT, packet+TCP_SOURCE_PORT, 2);
}
}
}
 
 
static void IPDhcp(const unsigned char *packet, int length, int state)
{
uint8 *packetOut, *ptr;
const uint8 *ptr2;
IPFrame *frame;
static int request=0;
 
if(state == 1)
{
//Create DHCP Discover
frame = IPFrameGet(0, 0);
if(frame == NULL)
return;
packetOut = frame->packet;
memset(packetOut, 0, 512);
memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover));
memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6);
memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions));
memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6);
IPSendPacket(NULL, frame, 400);
request = DHCP_DISCOVER;
DhcpRetrySeconds = RETRANSMIT_TIME;
}
else if(state == 2 && memcmp(packet+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6) == 0)
{
if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_OFFER && request == DHCP_DISCOVER)
{
//Process DHCP Offer and send DHCP Request
frame = IPFrameGet(0, 0);
if(frame == NULL)
return;
packetOut = frame->packet;
memset(packetOut, 0, 512);
memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover));
memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6);
memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions));
//memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6);
request = DHCP_REQUEST;
packetOut[DHCP_MAGIC_COOKIE+6] = DHCP_REQUEST;
ptr = packetOut+DHCP_MAGIC_COOKIE+sizeof(dhcpOptions)-1;
ptr[0] = DHCP_REQUEST_IP;
ptr[1] = 4;
memcpy(ptr+2, packet+DHCP_YOUR_IP, 4);
ptr[6] = DHCP_REQUEST_SERV_IP;
ptr[7] = 4;
memcpy(ptr+8, packet+DHCP_SERVER_IP, 4);
ptr[12] = DHCP_END_OPTION;
IPSendPacket(NULL, frame, 400);
}
else if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_ACK && request == DHCP_REQUEST)
{
//Process DHCP Ack
request = 0;
DhcpRetrySeconds = 3600*4;
memcpy(ipAddressPlasma, packet+DHCP_YOUR_IP, 4);
printf("IP=%d.%d.%d.%d ", ipAddressPlasma[0], ipAddressPlasma[1],
ipAddressPlasma[2], ipAddressPlasma[3]);
memcpy(ipAddressGateway, packet+DHCP_GATEWAY_IP, 4);
if(ipAddressGateway[0] == 0 && ipAddressGateway[1] == 0 &&
ipAddressGateway[2] == 0 && ipAddressGateway[3] == 0)
memcpy(ipAddressGateway, packet+DHCP_SERVER_IP, 4);
printf("GW=%d.%d.%d.%d ", ipAddressGateway[0], ipAddressGateway[1],
ipAddressGateway[2], ipAddressGateway[3]);
memcpy(ethernetAddressGateway, packet+ETHERNET_SOURCE, 6);
ptr2 = packet+DHCP_MAGIC_COOKIE+4;
while(ptr2[0] != DHCP_END_OPTION && (int)(ptr2 - packet) < length)
{
if(ptr2[0] == DHCP_PARAM_DNS)
{
ipAddressDns = (ptr2[2] << 24) | (ptr2[3] << 16) | (ptr2[4] << 8) | ptr2[5];
printf("DNS=%d.%d.%d.%d ", ptr2[2], ptr2[3], ptr2[4], ptr2[5]);
}
ptr2 += ptr2[1] + 2;
}
 
//Check if DHCP reply came from gateway
if(memcmp(packet+IP_SOURCE, ipAddressGateway, 4))
{
//Send ARP to gateway
frame = IPFrameGet(0, 0);
if(frame == NULL)
return;
packetOut = frame->packet;
memset(packetOut, 0, 512);
memset(packetOut+ETHERNET_DEST, 0xff, 6);
memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
packetOut[ETHERNET_FRAME_TYPE] = 0x08;
packetOut[ETHERNET_FRAME_TYPE+1] = 0x06;
packetOut[ARP_HARD_TYPE+1] = 0x01;
packetOut[ARP_PROT_TYPE] = 0x08;
packetOut[ARP_HARD_SIZE] = 0x06;
packetOut[ARP_PROT_SIZE] = 0x04;
packetOut[ARP_OP+1] = 1;
memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6);
memcpy(packetOut+ARP_IP_SENDER, ipAddressPlasma, 4);
memcpy(packetOut+ARP_IP_TARGET, ipAddressGateway, 4);
IPSendPacket(NULL, frame, 60);
}
}
}
}
 
 
static int IPProcessTCPPacket(IPFrame *frameIn)
{
uint32 seq, ack;
int length, ip_length, bytes;
IPSocket *socket, *socketNew;
IPFrame *frameOut, *frame2, *framePrev;
uint8 *packet, *packetOut;
 
packet = frameIn->packet;
length = frameIn->length;
 
ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1];
seq = (packet[TCP_SEQ] << 24) | (packet[TCP_SEQ+1] << 16) |
(packet[TCP_SEQ+2] << 8) | packet[TCP_SEQ+3];
ack = (packet[TCP_ACK] << 24) | (packet[TCP_ACK+1] << 16) |
(packet[TCP_ACK+2] << 8) | packet[TCP_ACK+3];
 
//Check if start of connection
if(packet[TCP_FLAGS] & TCP_FLAGS_SYN)
{
if(IPVerbose)
printf("S");
//Check if duplicate SYN
for(socket = SocketHead; socket; socket = socket->next)
{
if(socket->state != IP_LISTEN &&
packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 &&
memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0)
{
if(IPVerbose)
printf("s");
return 0;
}
}
 
//Find an open port
for(socket = SocketHead; socket; socket = socket->next)
{
if(socket->state == IP_LISTEN &&
packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
memcmp(packet+TCP_DEST_PORT, socket->headerRcv+TCP_DEST_PORT, 2) == 0)
{
//Create a new socket
frameOut = IPFrameGet(0, 0);
if(frameOut == NULL)
return 0;
socketNew = (IPSocket*)malloc(sizeof(IPSocket));
if(socketNew == NULL)
return 0;
memcpy(socketNew, socket, sizeof(IPSocket));
socketNew->state = IP_TCP;
socketNew->timeout = RETRANSMIT_TIME * 3;
socketNew->ack = seq;
socketNew->seq = socketNew->ack + 0x12345678;
socketNew->seqReceived = socketNew->seq;
 
//Send ACK
packetOut = frameOut->packet;
EthernetCreateResponse(packetOut, packet, length);
memcpy(socketNew->headerRcv, packet, TCP_SEQ);
memcpy(socketNew->headerSend, packetOut, TCP_SEQ);
packetOut[TCP_FLAGS] = TCP_FLAGS_SYN | TCP_FLAGS_ACK;
++socketNew->ack;
packetOut[TCP_DATA] = 2; //maximum segment size = 536
packetOut[TCP_DATA+1] = 4;
packetOut[TCP_DATA+2] = 2;
packetOut[TCP_DATA+3] = 24;
TCPSendPacket(socketNew, frameOut, TCP_DATA+4);
++socketNew->seq;
 
//Add socket to linked list
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
socketNew->next = SocketHead;
socketNew->prev = NULL;
if(SocketHead)
SocketHead->prev = socketNew;
SocketHead = socketNew;
OS_SemaphorePost(IPSemaphore);
return 0;
}
}
return 0;
}
 
//Find an open socket
for(socket = SocketHead; socket; socket = socket->next)
{
if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 &&
memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0)
{
break;
}
}
if(socket == NULL)
return 0;
 
//Check if FIN flag set
if(packet[TCP_FLAGS] & TCP_FLAGS_FIN)
{
socket->timeout = SOCKET_TIMEOUT;
if(IPVerbose)
printf("F");
frameOut = IPFrameGet(0, 0);
if(frameOut == NULL)
return 0;
packetOut = frameOut->packet;
packetOut[TCP_FLAGS] = TCP_FLAGS_ACK;
++socket->ack;
TCPSendPacket(socket, frameOut, TCP_DATA);
if(socket->state == IP_FIN_SERVER)
IPClose2(socket);
else
socket->state = IP_FIN_CLIENT;
}
else if(packet[TCP_FLAGS] & TCP_FLAGS_RST)
{
if(socket->state == IP_FIN_SERVER)
IPClose2(socket);
else
socket->state = IP_FIN_CLIENT;
}
else
{
//TCP payload
if(packet[TCP_HEADER_LENGTH] != 0x50)
{
if(IPVerbose)
printf("length error\n");
return 0;
}
 
//Check if packets can be removed from retransmition list
if(ack != socket->seqReceived)
{
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
for(frame2 = FrameResendHead; frame2; )
{
framePrev = frame2;
frame2 = frame2->next;
if(framePrev->socket == socket && (int)(ack - framePrev->seqEnd) >= 0)
{
//Remove packet from retransmition queue
socket->timeout = SOCKET_TIMEOUT;
FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
FrameFree(framePrev);
}
}
OS_SemaphorePost(IPSemaphore);
socket->seqReceived = ack;
}
 
bytes = ip_length - (TCP_DATA - IP_VERSION_LENGTH);
 
//Copy packet into socket
if(socket->ack == seq && bytes > 0)
{
//Insert packet into socket linked list
socket->timeout = SOCKET_TIMEOUT;
if(IPVerbose)
printf("D");
FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn);
socket->ack += bytes;
 
//Ack data
frameOut = IPFrameGet(FRAME_MIN_COUNT, 0);
if(frameOut)
{
frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
TCPSendPacket(socket, frameOut, TCP_DATA);
}
 
//Notify application
if(socket->funcPtr)
socket->funcPtr(socket);
return 1;
}
}
return 0;
}
 
 
int IPProcessEthernetPacket(IPFrame *frameIn)
{
int ip_length, rc;
IPSocket *socket;
IPFrame *frameOut;
uint8 *packet, *packetOut;
 
packet = frameIn->packet;
 
if(packet[ETHERNET_FRAME_TYPE] != 0x08 || frameIn->length > PACKET_SIZE)
return 0; //wrong ethernet type, packet not used
 
//ARP?
if(packet[ETHERNET_FRAME_TYPE+1] == 0x06)
{
//Check if ARP reply
if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) == 0 &&
packet[ARP_OP+1] == 2 && memcmp(packet+ARP_IP_SENDER, ipAddressGateway, 4) == 0)
{
//Found MAC address for gateway
memcpy(ethernetAddressGateway, packet+ARP_ETHERNET_SENDER, 6);
return 0;
}
 
//Check if ARP request
if(memcmp(packet+ETHERNET_DEST, ethernetAddressNull, 6) ||
packet[ARP_OP] != 0 || packet[ARP_OP+1] != 1 ||
memcmp(packet+ARP_IP_TARGET, ipAddressPlasma, 4))
return 0;
//Create ARP response
frameOut = IPFrameGet(0, 0);
if(frameOut == NULL)
return 0;
packetOut = frameOut->packet;
memcpy(packetOut, packet, frameIn->length);
memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6);
memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
packetOut[ARP_OP+1] = 2; //ARP reply
memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6);
memcpy(packetOut+ARP_IP_SENDER, packet+ARP_IP_TARGET, 4);
memcpy(packetOut+ARP_ETHERNET_TARGET, packet+ARP_ETHERNET_SENDER, 6);
memcpy(packetOut+ARP_IP_TARGET, packet+ARP_IP_SENDER, 4);
IPSendPacket(NULL, frameOut, frameIn->length);
return 0;
}
 
//Check if proper type of packet
ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1];
if(frameIn->length < UDP_DATA || ip_length > frameIn->length - IP_VERSION_LENGTH)
return 0;
if(packet[ETHERNET_FRAME_TYPE+1] != 0x00 ||
packet[IP_VERSION_LENGTH] != 0x45)
return 0;
 
//Check if DHCP reply
if(packet[IP_PROTOCOL] == 0x11 &&
packet[UDP_SOURCE_PORT] == 0 && packet[UDP_SOURCE_PORT+1] == 67 &&
packet[UDP_DEST_PORT] == 0 && packet[UDP_DEST_PORT+1] == 68)
{
IPDhcp(packet, frameIn->length, 2); //DHCP reply
return 0;
}
 
//Check if correct destination address
if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) ||
memcmp(packet+IP_DEST, ipAddressPlasma, 4))
return 0;
rc = EthernetVerifyChecksums(packet, frameIn->length);
//if(rc)
//{
// printf("C ");
// return;
//}
 
//PING request?
if(packet[IP_PROTOCOL] == 1)
{
if(packet[PING_TYPE] != 8)
return 0;
frameOut = IPFrameGet(0, 0);
if(frameOut == NULL)
return 0;
packetOut = frameOut->packet;
EthernetCreateResponse(packetOut, packet, frameIn->length);
frameOut->packet[PING_TYPE] = 0; //PING reply
IPSendPacket(NULL, frameOut, frameIn->length);
return 0;
}
 
//TCP packet?
if(packet[IP_PROTOCOL] == 0x06)
{
return IPProcessTCPPacket(frameIn);
}
 
//UDP packet?
if(packet[IP_PROTOCOL] == 0x11)
{
//Find open socket
for(socket = SocketHead; socket; socket = socket->next)
{
if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 &&
memcmp(packet+UDP_SOURCE_PORT, socket->headerRcv+UDP_SOURCE_PORT, 2) == 0)
{
break;
}
}
 
if(socket == NULL)
{
//Find listening socket
for(socket = SocketHead; socket; socket = socket->next)
{
if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
memcmp(packet+UDP_DEST_PORT, socket->headerRcv+UDP_DEST_PORT, 2) == 0)
{
break;
}
}
}
 
if(socket)
{
if(IPVerbose)
printf("U");
FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn);
socket->funcPtr(socket);
return 1;
}
}
return 0;
}
 
 
void IPMainThread(void *Arg)
{
uint32 message[4];
int rc;
IPFrame *frame, *frameOut=NULL;
uint32 ticks, ticksLast;
(void)Arg;
 
ticksLast = OS_ThreadTime();
memset(message, 0, sizeof(message));
 
for(;;)
{
Led(0);
rc = OS_MQueueGet(IPMQueue, message, 10);
if(rc == 0)
{
frame = (IPFrame*)message[1];
if(message[0] == 0) //frame received
{
Led(1);
frame->length = (uint16)message[2];
rc = IPProcessEthernetPacket(frame);
if(rc == 0)
FrameFree(frame);
}
else if(message[0] == 1) //frame sent
{
Led(2);
assert(frame == frameOut);
IPFrameReschedule(frame);
frameOut = NULL;
}
else if(message[0] == 2) //frame ready to send
{
}
}
 
if(frameOut == NULL)
{
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
frameOut = FrameSendTail;
if(frameOut)
FrameRemove(&FrameSendHead, &FrameSendTail, frameOut);
OS_SemaphorePost(IPSemaphore);
if(frameOut)
{
Led(4);
UartPacketSend(frameOut->packet, frameOut->length);
}
}
 
ticks = OS_ThreadTime();
if(ticks - ticksLast > 100)
{
//Led(8);
IPTick();
ticksLast = ticks;
}
}
}
 
 
static uint8 *MyPacketGet(void)
{
return (uint8*)IPFrameGet(0, 0);
}
 
 
//Set FrameSendFunction only if single threaded
void IPInit(IPFuncPtr FrameSendFunction)
{
int i;
IPFrame *frame;
 
FrameSendFunc = FrameSendFunction;
IPSemaphore = OS_SemaphoreCreate("IPSem", 1);
FrameGetSem = OS_SemaphoreCreate("FrameGet", 0);
IPMQueue = OS_MQueueCreate("IPMQ", FRAME_COUNT*2, 32);
for(i = 0; i < FRAME_COUNT; ++i)
{
frame = (IPFrame*)malloc(sizeof(IPFrame));
memset(frame, 0, sizeof(IPFrame));
frame->next = FrameFreeHead;
frame->prev = NULL;
FrameFreeHead = frame;
}
UartPacketConfig(MyPacketGet, PACKET_SIZE, IPMQueue);
if(FrameSendFunction == NULL)
OS_ThreadCreate("TCP/IP", IPMainThread, NULL, 128, 6000);
 
IPDhcp(NULL, 360, 1); //Send DHCP request
}
 
 
//To open a socket for listen set IPAddress to 0
IPSocket *IPOpen(IPMode_e Mode, uint32 IPAddress, uint32 Port, IPFuncPtr funcPtr)
{
IPSocket *socket;
uint8 *ptr;
static int portSource=0x1000;
(void)Mode;
(void)IPAddress;
 
socket = (IPSocket*)malloc(sizeof(IPSocket));
if(socket == NULL)
return socket;
memset(socket, 0, sizeof(IPSocket));
socket->prev = NULL;
socket->state = IP_LISTEN;
socket->timeout = 0;
socket->frameReadHead = NULL;
socket->frameReadTail = NULL;
socket->readOffset = 0;
socket->funcPtr = funcPtr;
socket->userData = 0;
socket->userFunc = NULL;
socket->userPtr = NULL;
ptr = socket->headerSend;
 
if(IPAddress == 0)
{
//Setup listing port
socket->headerRcv[TCP_DEST_PORT] = (uint8)(Port >> 8);
socket->headerRcv[TCP_DEST_PORT+1] = (uint8)Port;
}
else
{
//Setup receive port
socket->headerRcv[TCP_DEST_PORT] = (uint8)(portSource >> 8);
socket->headerRcv[TCP_DEST_PORT+1] = (uint8)portSource;
 
//Setup sending packet
memset(ptr, 0, UDP_LENGTH);
memcpy(ptr+ETHERNET_DEST, ethernetAddressGateway, 6);
memcpy(ptr+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
ptr[ETHERNET_FRAME_TYPE] = 0x08;
ptr[IP_VERSION_LENGTH] = 0x45;
ptr[IP_TIME_TO_LIVE] = 0x80;
ptr[IP_PROTOCOL] = 0x11; //UDP
memcpy(ptr+IP_SOURCE, ipAddressPlasma, 4);
ptr[IP_DEST] = (uint8)(IPAddress >> 24);
ptr[IP_DEST+1] = (uint8)(IPAddress >> 16);
ptr[IP_DEST+2] = (uint8)(IPAddress >> 8);
ptr[IP_DEST+3] = (uint8)IPAddress;
ptr[TCP_SOURCE_PORT] = (uint8)(portSource >> 8);
ptr[TCP_SOURCE_PORT+1] = (uint8)portSource;
++portSource;
ptr[TCP_DEST_PORT] = (uint8)(Port >> 8);
ptr[TCP_DEST_PORT+1] = (uint8)Port;
}
 
if(Mode == IP_MODE_TCP)
{
socket->headerRcv[IP_PROTOCOL] = 0x06; //TCP
ptr[IP_PROTOCOL] = 0x06;
}
else if(Mode == IP_MODE_UDP)
{
socket->state = IP_UDP;
socket->headerRcv[IP_PROTOCOL] = 0x11; //UDP
ptr[IP_PROTOCOL] = 0x11;
}
 
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
socket->next = SocketHead;
SocketHead = socket;
OS_SemaphorePost(IPSemaphore);
return socket;
}
 
 
void IPWriteFlush(IPSocket *Socket)
{
uint8 *packetOut;
if(Socket->frameSend && Socket->state != IP_UDP)
{
packetOut = Socket->frameSend->packet;
packetOut[TCP_FLAGS] = TCP_FLAGS_ACK;
TCPSendPacket(Socket, Socket->frameSend, TCP_DATA + Socket->sendOffset);
Socket->seq += Socket->sendOffset;
Socket->frameSend = NULL;
Socket->sendOffset = 0;
}
}
 
 
uint32 IPWrite(IPSocket *Socket, const uint8 *Buf, uint32 Length)
{
IPFrame *frameOut;
uint8 *packetOut;
uint32 bytes, count=0;
int offset;
 
//printf("IPWrite(0x%x, %d)", Socket, Length);
while(Length)
{
if(Socket->frameSend == NULL)
{
Socket->frameSend = IPFrameGet(FRAME_MIN_COUNT, 0);
Socket->sendOffset = 0;
}
frameOut = Socket->frameSend;
offset = Socket->sendOffset;
if(frameOut == NULL)
break;
packetOut = frameOut->packet;
bytes = 512 - offset;
if(bytes > Length)
bytes = Length;
Socket->sendOffset += bytes;
 
if(Socket->state != IP_UDP)
{
memcpy(packetOut+TCP_DATA+offset, Buf, bytes);
if(Socket->sendOffset >= 512)
IPWriteFlush(Socket);
}
else //UDP
{
memcpy(packetOut+UDP_DATA+offset, Buf, bytes);
memcpy(packetOut, Socket->headerSend, UDP_LENGTH);
IPSendPacket(Socket, Socket->frameSend, UDP_DATA + Socket->sendOffset);
Socket->frameSend = NULL;
}
count += bytes;
Buf += bytes;
Length -= bytes;
}
return count;
}
 
 
uint32 IPRead(IPSocket *Socket, uint8 *Buf, uint32 Length)
{
IPFrame *frame, *frame2;
int count=0, bytes, offset;
 
if(Socket->state == IP_TCP)
offset = TCP_DATA;
else
offset = UDP_DATA;
 
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
for(frame = Socket->frameReadTail; Length && frame; )
{
bytes = frame->length - offset - Socket->readOffset;
if(bytes > (int)Length)
bytes = Length;
memcpy(Buf, frame->packet + offset + Socket->readOffset, bytes);
Buf += bytes;
Socket->readOffset += bytes;
Length -= bytes;
count += bytes;
 
//Check if done with packet
frame2 = frame;
frame = frame->prev;
if(Socket->readOffset == frame2->length - offset)
{
//Remove packet from socket linked list
Socket->readOffset = 0;
FrameRemove(&Socket->frameReadHead, &Socket->frameReadTail, frame2);
FrameFree(frame2);
}
}
OS_SemaphorePost(IPSemaphore);
return count;
}
 
 
static void IPClose2(IPSocket *Socket)
{
IPFrame *frame, *framePrev;
 
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
 
//Remove packets from send list
for(frame = FrameSendHead; frame; )
{
framePrev = frame;
frame = frame->next;
if(framePrev->socket == Socket)
{
FrameRemove(&FrameSendHead, &FrameSendTail, framePrev);
FrameFree(framePrev);
}
}
 
//Remove packets from retransmision list
for(frame = FrameResendHead; frame; )
{
framePrev = frame;
frame = frame->next;
if(framePrev->socket == Socket)
{
FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
FrameFree(framePrev);
}
}
 
//Remove packets from socket read linked list
for(frame = Socket->frameReadHead; frame; )
{
framePrev = frame;
frame = frame->next;
FrameRemove(&Socket->frameReadHead, &Socket->frameReadTail, framePrev);
FrameFree(framePrev);
}
 
//Remove socket
if(Socket->prev == NULL)
SocketHead = Socket->next;
else
Socket->prev->next = Socket->next;
if(Socket->next)
Socket->next->prev = Socket->prev;
free(Socket);
OS_SemaphorePost(IPSemaphore);
}
 
 
void IPClose(IPSocket *Socket)
{
IPFrame *frameOut;
 
IPWriteFlush(Socket);
frameOut = IPFrameGet(0, 0);
if(frameOut == 0)
return;
frameOut->packet[TCP_FLAGS] = TCP_FLAGS_FIN | TCP_FLAGS_ACK;
TCPSendPacket(Socket, frameOut, TCP_DATA);
++Socket->seq;
if(Socket->state == IP_TCP)
Socket->state = IP_FIN_SERVER;
if(Socket->state == IP_FIN_CLIENT)
IPClose2(Socket);
}
 
 
//static void ShowIP(IPSocket *socket, uint32 ipAddress)
//{
// (void)socket;
// printf("IP=0x%x\n", ipAddress);
//}
 
 
void IPTick(void)
{
IPFrame *frame, *frame2;
IPSocket *socket, *socket2;
 
if(IPVerbose && (Seconds % 60) == 0)
printf("T");
++Seconds;
if(--DhcpRetrySeconds <= 0)
IPDhcp(NULL, 400, 1); //DHCP request
//if(Seconds == 10)
// IPResolve("plasmacpu.no-ip.org", ShowIP);
 
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
 
//Retransmit timeout packets
for(frame = FrameResendHead; frame; )
{
frame2 = frame;
frame = frame->next;
if(--frame2->timeout == 0)
{
if(IPVerbose)
printf("r");
FrameRemove(&FrameResendHead, &FrameResendTail, frame2);
OS_SemaphorePost(IPSemaphore);
IPSendFrame(frame2);
OS_SemaphorePend(IPSemaphore, OS_WAIT_FOREVER);
}
}
 
//Close timed out sockets
for(socket = SocketHead; socket; )
{
socket2 = socket;
socket = socket->next;
if(socket2->timeout && --socket2->timeout == 0)
{
socket2->timeout = 10;
if(socket2->state == IP_CLOSED)
{
IPClose2(socket2);
}
else
{
if(IPVerbose)
printf("t");
if(socket2->state == IP_TCP)
IPClose(socket2);
else if(socket2->state == IP_FIN_SERVER)
IPClose2(socket2);
}
}
}
OS_SemaphorePost(IPSemaphore);
}
 
 
static void DnsCallback(IPSocket *socket)
{
uint8 buf[200], *ptr;
uint32 ipAddress;
int i, length;
 
memset(buf, 0, sizeof(buf));
IPRead(socket, buf, sizeof(buf));
if(buf[DNS_NUM_ANSWERS_RR+1])
{
ptr = buf + DNS_QUESTIONS;
while(*ptr)
++ptr;
++ptr;
ptr += 4;
for(i = 0; (int)(ptr - buf) < sizeof(buf) && i < buf[DNS_NUM_ANSWERS_RR+1]; ++i)
{
if(ptr[2] == 0 && ptr[3] == 1 && ptr[4] == 0 && ptr[5] == 1)
{
ipAddress = (ptr[12] << 24) | (ptr[13] << 16) | (ptr[14] << 8) | ptr[15];
printf("ipAddress = %d.%d.%d.%d\n", ptr[12], ptr[13], ptr[14], ptr[16]);
socket->userData = ipAddress;
if(socket->userFunc)
{
socket->userFunc(socket, ipAddress);
}
break;
}
length = (ptr[10] << 8) | ptr[11];
ptr += 12 + length;
}
}
if(FrameSendFunc)
IPClose(socket);
}
 
 
uint32 IPResolve(char *Name, IPFuncPtr resolvedFunc)
{
uint8 buf[200], *ptr;
int length, i;
IPSocket *socket;
uint32 ipAddress=0;
 
socket = IPOpen(IP_MODE_UDP, ipAddressDns, DNS_PORT, DnsCallback);
memset(buf, 0, sizeof(buf));
buf[DNS_ID+1] = 1;
buf[DNS_FLAGS] = 1;
buf[DNS_NUM_QUESTIONS+1] = 1;
 
//Setup name
ptr = buf + DNS_QUESTIONS;
strncpy((char*)ptr+1, Name, 100);
ptr[0] = 1;
while(ptr[0])
{
for(i = 0; i < 100; ++i)
{
if(ptr[i+1] == '.' || ptr[i+1] == 0)
{
ptr[0] = (uint8)i;
ptr += i+1;
break;
}
}
}
++ptr;
ptr[1] = DNS_QUERY_TYPE_IP;
ptr[3] = DNS_QUERY_CLASS;
length = (int)(ptr - buf) + 4;
if(length < 60)
length = 60;
 
socket->userFunc = (IPFuncPtr)resolvedFunc;
socket->userData = 0;
IPWrite(socket, buf, length);
 
if(FrameSendFunc == NULL)
{
for(i = 0; i < 1000 && socket->userData == 0; ++i)
OS_ThreadSleep(1);
ipAddress = socket->userData;
IPClose(socket);
}
return ipAddress;
}
 
/trunk/kernel/tcpip.h
0,0 → 1,90
/*--------------------------------------------------------------------
* TITLE: Plasma TCP/IP Protocol Stack
* AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
* DATE CREATED: 4/22/06
* FILENAME: tcpip.h
* PROJECT: Plasma CPU core
* COPYRIGHT: Software placed into the public domain by the author.
* Software 'as is' without warranty. Author liable for nothing.
* DESCRIPTION:
* Plasma TCP/IP Protocol Stack
*--------------------------------------------------------------------*/
#define PACKET_SIZE 600
#define FRAME_COUNT 50
#define FRAME_MIN_COUNT 5
#define RETRANSMIT_TIME 4
#define SOCKET_TIMEOUT 20
 
typedef enum IPMode_e {
IP_MODE_UDP,
IP_MODE_TCP
} IPMode_e;
 
typedef enum IPState_e {
IP_LISTEN,
IP_UDP,
IP_SYN,
IP_TCP,
IP_FIN_CLIENT,
IP_FIN_SERVER,
IP_CLOSED
} IPState_e;
 
typedef void (*IPFuncPtr)();
 
typedef struct IPFrame {
uint8 packet[PACKET_SIZE];
struct IPFrame *next, *prev;
struct IPSocket *socket;
uint32 seqEnd;
uint16 length, timeout;
uint8 state, retryCnt;
} IPFrame;
 
typedef struct IPSocket {
struct IPSocket *next, *prev;
IPState_e state;
uint32 seq;
uint32 seqReceived;
uint32 ack;
uint32 timeout;
uint8 headerSend[38];
uint8 headerRcv[38];
struct IPFrame *frameReadHead;
struct IPFrame *frameReadTail;
int readOffset;
struct IPFrame *frameSend;
int sendOffset;
IPFuncPtr funcPtr;
IPFuncPtr userFunc;
void *userPtr;
uint32 userData;
} IPSocket;
 
//ethernet.c
void EthernetSendPacket(const unsigned char *packet, int length);
 
//tcpip.c
void IPInit(IPFuncPtr FrameSendFunction);
IPFrame *IPFrameGet(int freeCount, int pend);
int IPProcessEthernetPacket(IPFrame *frameIn);
void IPTick(void);
 
IPSocket *IPOpen(IPMode_e Mode, uint32 IPAddress, uint32 Port, IPFuncPtr funcPtr);
void IPWriteFlush(IPSocket *Socket);
uint32 IPWrite(IPSocket *Socket, const uint8 *Buf, uint32 Length);
uint32 IPRead(IPSocket *Socket, uint8 *Buf, uint32 Length);
void IPClose(IPSocket *Socket);
uint32 IPResolve(char *Name, IPFuncPtr resolvedFunc);
 
//http.c
#define HTML_LENGTH_CALLBACK -2
#define HTML_LENGTH_LIST_END -1
typedef struct PageEntry_s {
const char *name;
int length;
const char *page;
} PageEntry_t;
void HttpInit(const PageEntry_t *Pages, int UseFiles);
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.