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); |
|
|