1
0
mirror of git://projects.qi-hardware.com/nn-usb-fpga.git synced 2024-12-13 22:33:09 +02:00
nn-usb-fpga/plasma/kernel/tcpip.c
2010-04-21 20:01:38 -05:00

1680 lines
52 KiB
C

/*--------------------------------------------------------------------
* 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"
#define IPPRINTF
#include "tcpip.h"
//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_PSH 8
#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 ethernetAddressGateway[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
#ifndef WIN32
static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4};
#else
static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd5};
#endif
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_Mutex_t *IPMutex;
static int FrameFreeCount;
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;
static OS_Thread_t *IPThread;
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 unsigned char dhcpOptions[] = {
0x63, 0x82, 0x53, 0x63, //cookie
0x35, 0x01, 0x01, //DHCP Discover
0x3d, 0x07, 0x01, 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //Client identifier
#ifndef WIN32
0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'a', //Host name
#else
0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'b', //Host name
#endif
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)
{
IPFrame *frame=NULL;
uint32 state;
state = OS_CriticalBegin();
if(FrameFreeCount > freeCount)
{
frame = FrameFreeHead;
if(FrameFreeHead)
{
FrameFreeHead = FrameFreeHead->next;
--FrameFreeCount;
}
}
OS_CriticalEnd(state);
if(frame)
{
assert(frame->state == 0);
frame->state = 1;
}
return frame;
}
static void FrameFree(IPFrame *frame)
{
uint32 state;
assert(frame->state == 1);
frame->state = 0;
state = OS_CriticalBegin();
frame->next = FrameFreeHead;
FrameFreeHead = frame;
++FrameFreeCount;
OS_CriticalEnd(state);
}
static void FrameInsert(IPFrame **head, IPFrame **tail, IPFrame *frame)
{
assert(frame->state == 1);
frame->state = 2;
OS_MutexPend(IPMutex);
frame->prev = NULL;
frame->next = *head;
if(*head)
(*head)->prev = frame;
*head = frame;
if(*tail == NULL)
*tail = frame;
OS_MutexPost(IPMutex);
}
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_SYN))
++length;
if(frame->socket == NULL || frame->socket->state == IP_UDP || length == 0 ||
frame->socket->state == IP_PING || ++frame->retryCnt > 4)
{
FrameFree(frame); //can't be ACK'ed
}
#ifdef WIN32
else if(FrameFreeCount < FRAME_COUNT_SYNC)
{
FrameFree(frame); //can't be ACK'ed
}
#endif
else
{
//Put on resend list until TCP ACK'ed
frame->timeout = (short)(RETRANSMIT_TIME * frame->retryCnt);
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) //ICMP & 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;
}
}
length2 = length - TCP_DATA;
if(socket && (packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN)))
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, count;
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;
count = RECEIVE_WINDOW - (socket->ack - socket->ackProcessed);
if(count < 0)
count = 0;
packet[TCP_WINDOW_SIZE] = (uint8)(count >> 8);
packet[TCP_WINDOW_SIZE+1] = (uint8)count;
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);
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 = 2;
}
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);
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);
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);
}
}
}
}
uint32 IPAddressSelf(void)
{
return (ipAddressPlasma[0] << 24) | (ipAddressPlasma[1] << 16) |
(ipAddressPlasma[2] << 8) | ipAddressPlasma[3];
}
static int IPProcessTCPPacket(IPFrame *frameIn)
{
uint32 seq, ack;
int length, ip_length, bytes, rc=0, notify=0;
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 | TCP_FLAGS_ACK)) == 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(FRAME_COUNT_SYNC);
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 = SOCKET_TIMEOUT;
socketNew->ack = seq;
socketNew->ackProcessed = seq + 1;
socketNew->seq = socketNew->ack + 0x12345678;
socketNew->seqReceived = socketNew->seq;
socketNew->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1];
//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_MutexPend(IPMutex);
socketNew->next = SocketHead;
socketNew->prev = NULL;
if(SocketHead)
SocketHead->prev = socketNew;
SocketHead = socketNew;
OS_MutexPost(IPMutex);
if(socketNew->funcPtr)
OS_Job(socketNew->funcPtr, socketNew, 0, 0);
return 0;
}
}
//Send reset
frameOut = IPFrameGet(0);
if(frameOut == NULL)
return 0;
packetOut = frameOut->packet;
EthernetCreateResponse(packetOut, packet, TCP_DATA);
memset(packetOut+TCP_SEQ, 0, 4);
++seq;
packetOut[TCP_ACK] = (uint8)(seq >> 24);
packetOut[TCP_ACK+1] = (uint8)(seq >> 16);
packetOut[TCP_ACK+2] = (uint8)(seq >> 8);
packetOut[TCP_ACK+3] = (uint8)seq;
packetOut[TCP_HEADER_LENGTH] = 0x50;
packetOut[TCP_FLAGS] = TCP_FLAGS_RST;
IPSendPacket(NULL, frameOut, TCP_DATA);
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;
}
//Determine window
socket->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1];
bytes = ip_length - (TCP_DATA - IP_VERSION_LENGTH);
//Check if packets can be removed from retransmition list
if(packet[TCP_FLAGS] & TCP_FLAGS_ACK)
{
if(ack != socket->seqReceived)
{
OS_MutexPend(IPMutex);
for(frame2 = FrameResendHead; frame2; )
{
framePrev = frame2;
frame2 = frame2->next;
if(framePrev->socket == socket && (int)(ack - framePrev->seqEnd) >= 0)
{
//Remove packet from retransmition queue
if(socket->timeout)
socket->timeout = socket->timeoutReset;
FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
FrameFree(framePrev);
}
}
OS_MutexPost(IPMutex);
socket->seqReceived = ack;
socket->resentDone = 0;
}
else if(ack == socket->seqReceived && bytes == 0 &&
(packet[TCP_FLAGS] & (TCP_FLAGS_RST | TCP_FLAGS_FIN)) == 0 &&
socket->resentDone == 0)
{
//Detected that packet was lost, resend all
if(IPVerbose)
printf("A");
OS_MutexPend(IPMutex);
for(frame2 = FrameResendHead; frame2; )
{
framePrev = frame2;
frame2 = frame2->next;
if(framePrev->socket == socket)
{
//Remove packet from retransmition queue
FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
IPSendFrame(framePrev);
}
}
OS_MutexPost(IPMutex);
socket->resentDone = 1;
}
}
//Check if SYN/ACK
if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) ==
(TCP_FLAGS_SYN | TCP_FLAGS_ACK))
{
//Ack SYN/ACK
socket->ack = seq + 1;
socket->ackProcessed = seq + 1;
frameOut = IPFrameGet(FRAME_COUNT_SEND);
if(frameOut)
{
frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
TCPSendPacket(socket, frameOut, TCP_DATA);
}
if(socket->funcPtr)
OS_Job(socket->funcPtr, socket, 0, 0);
return 0;
}
if(packet[TCP_HEADER_LENGTH] != 0x50)
{
if(IPVerbose)
printf("length error\n");
return 0;
}
//Check if RST flag set
if(packet[TCP_FLAGS] & TCP_FLAGS_RST)
{
notify = 1;
if(socket->state == IP_FIN_SERVER)
IPClose2(socket);
else if(socket->state == IP_TCP)
socket->state = IP_FIN_CLIENT;
}
//Copy packet into socket
else if(socket->ack == seq && bytes > 0)
{
//Insert packet into socket linked list
notify = 1;
if(socket->timeout)
socket->timeout = socket->timeoutReset;
if(IPVerbose)
printf("D");
if(frameIn->length > ip_length + IP_VERSION_LENGTH)
frameIn->length = (uint16)(ip_length + IP_VERSION_LENGTH);
FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn);
socket->ack += bytes;
//Ack data
frameOut = IPFrameGet(FRAME_COUNT_SEND);
if(frameOut)
{
frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
TCPSendPacket(socket, frameOut, TCP_DATA);
}
//Using frame
rc = 1;
}
else if(bytes)
{
//Ack with current offset since data missing
frameOut = IPFrameGet(FRAME_COUNT_SEND);
if(frameOut)
{
frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
TCPSendPacket(socket, frameOut, TCP_DATA);
}
}
//Check if FIN flag set
if(packet[TCP_FLAGS] & TCP_FLAGS_FIN && socket->ack >= seq)
{
notify = 1;
socket->timeout = SOCKET_TIMEOUT;
if(IPVerbose)
printf("F");
frameOut = IPFrameGet(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 if(socket->state == IP_TCP)
socket->state = IP_FIN_CLIENT;
}
//Notify application
if(socket->funcPtr && notify)
OS_Job(socket->funcPtr, socket, 0, 0);
return rc;
}
int IPProcessEthernetPacket(IPFrame *frameIn, int length)
{
int ip_length, rc;
IPSocket *socket;
IPFrame *frameOut;
uint8 *packet, *packetOut;
packet = frameIn->packet;
frameIn->length = (uint16)length;
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(packet[ARP_OP] != 0 || packet[ARP_OP+1] != 1 ||
memcmp(packet+ARP_IP_TARGET, ipAddressPlasma, 4))
return 0;
//Create ARP response
frameOut = IPFrameGet(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);
#ifndef WIN32
if(rc && FrameSendFunc)
{
printf("C ");
return 0;
}
#endif
//PING request?
if(packet[IP_PROTOCOL] == 1)
{
if(packet[PING_TYPE] == 0) //PING reply
{
for(socket = SocketHead; socket; socket = socket->next)
{
if(socket->state == IP_PING &&
memcmp(packet+IP_SOURCE, socket->headerSend+IP_DEST, 4) == 0)
{
OS_Job(socket->funcPtr, socket, 0, 0);
return 0;
}
}
}
if(packet[PING_TYPE] != 8)
return 0;
frameOut = IPFrameGet(FRAME_COUNT_SEND);
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)
{
EthernetCreateResponse(socket->headerSend, packet, UDP_DATA);
break;
}
}
}
if(socket)
{
if(IPVerbose)
printf("U");
FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn);
OS_Job(socket->funcPtr, socket, 0, 0);
return 1;
}
}
return 0;
}
#ifndef WIN32
static 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(7, 0);
rc = OS_MQueueGet(IPMQueue, message, 10);
if(rc == 0)
{
frame = (IPFrame*)message[1];
if(message[0] == 0) //frame received
{
Led(7, 1);
frame->length = (uint16)message[2];
rc = IPProcessEthernetPacket(frame, frame->length);
if(rc == 0)
FrameFree(frame);
}
else if(message[0] == 1) //frame sent
{
Led(7, 2);
assert(frame == frameOut);
IPFrameReschedule(frame);
frameOut = NULL;
}
else if(message[0] == 2) //frame ready to send
{
}
}
if(frameOut == NULL)
{
OS_MutexPend(IPMutex);
frameOut = FrameSendTail;
if(frameOut)
FrameRemove(&FrameSendHead, &FrameSendTail, frameOut);
OS_MutexPost(IPMutex);
if(frameOut)
{
Led(7, 4);
UartPacketSend(frameOut->packet, frameOut->length);
}
}
ticks = OS_ThreadTime();
if(ticks - ticksLast > 100)
{
IPTick();
ticksLast = ticks;
}
}
}
#endif
uint8 *MyPacketGet(void)
{
return (uint8*)IPFrameGet(FRAME_COUNT_RCV);
}
//Set FrameSendFunction only if single threaded
void IPInit(IPFuncPtr frameSendFunction, uint8 macAddress[6], char name[6])
{
int i;
IPFrame *frame;
if(macAddress)
memcpy(ethernetAddressPlasma, macAddress, 6);
if(name)
memcpy(dhcpOptions+18, name, 6);
FrameSendFunc = frameSendFunction;
IPMutex = OS_MutexCreate("IPSem");
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;
}
FrameFreeCount = FRAME_COUNT;
#ifndef WIN32
UartPacketConfig(MyPacketGet, PACKET_SIZE, IPMQueue);
if(frameSendFunction == NULL)
IPThread = OS_ThreadCreate("TCP/IP", IPMainThread, NULL, 240, 6000);
#endif
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 *ptrSend, *ptrRcv;
IPFrame *frame;
static int portSource=0x1007;
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->timeoutReset = SOCKET_TIMEOUT;
socket->frameReadHead = NULL;
socket->frameReadTail = NULL;
socket->readOffset = 0;
socket->funcPtr = funcPtr;
socket->userData = 0;
socket->userFunc = NULL;
socket->userPtr = NULL;
socket->seqWindow = 2048;
ptrSend = socket->headerSend;
ptrRcv = socket->headerRcv;
if(ipAddress == 0)
{
//Setup listing port
socket->headerRcv[TCP_DEST_PORT] = (uint8)(port >> 8);
socket->headerRcv[TCP_DEST_PORT+1] = (uint8)port;
}
else
{
//Setup sending packet
memset(ptrSend, 0, UDP_LENGTH);
memset(ptrRcv, 0, UDP_LENGTH);
//Setup Ethernet
if(ipAddress != IPAddressSelf())
memcpy(ptrSend+ETHERNET_DEST, ethernetAddressGateway, 6);
else
memcpy(ptrSend+ETHERNET_DEST, ethernetAddressPlasma, 6);
memcpy(ptrSend+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
ptrSend[ETHERNET_FRAME_TYPE] = 0x08;
//Setup IP
ptrSend[IP_VERSION_LENGTH] = 0x45;
ptrSend[IP_TIME_TO_LIVE] = 0x80;
//Setup IP addresses
memcpy(ptrSend+IP_SOURCE, ipAddressPlasma, 4);
ptrSend[IP_DEST] = (uint8)(ipAddress >> 24);
ptrSend[IP_DEST+1] = (uint8)(ipAddress >> 16);
ptrSend[IP_DEST+2] = (uint8)(ipAddress >> 8);
ptrSend[IP_DEST+3] = (uint8)ipAddress;
ptrRcv[IP_SOURCE] = (uint8)(ipAddress >> 24);
ptrRcv[IP_SOURCE+1] = (uint8)(ipAddress >> 16);
ptrRcv[IP_SOURCE+2] = (uint8)(ipAddress >> 8);
ptrRcv[IP_SOURCE+3] = (uint8)ipAddress;
memcpy(ptrRcv+IP_DEST, ipAddressPlasma, 4);
//Setup ports
ptrSend[TCP_SOURCE_PORT] = (uint8)(portSource >> 8);
ptrSend[TCP_SOURCE_PORT+1] = (uint8)portSource;
ptrSend[TCP_DEST_PORT] = (uint8)(port >> 8);
ptrSend[TCP_DEST_PORT+1] = (uint8)port;
ptrRcv[TCP_SOURCE_PORT] = (uint8)(port >> 8);
ptrRcv[TCP_SOURCE_PORT+1] = (uint8)port;
ptrRcv[TCP_DEST_PORT] = (uint8)(portSource >> 8);
ptrRcv[TCP_DEST_PORT+1] = (uint8)portSource;
++portSource;
}
if(mode == IP_MODE_TCP)
{
if(ipAddress)
socket->state = IP_TCP;
else
socket->state = IP_LISTEN;
ptrSend[IP_PROTOCOL] = 0x06; //TCP
ptrRcv[IP_PROTOCOL] = 0x06;
}
else if(mode == IP_MODE_UDP)
{
socket->state = IP_UDP;
ptrSend[IP_PROTOCOL] = 0x11; //UDP
ptrRcv[IP_PROTOCOL] = 0x11;
}
else if(mode == IP_MODE_PING)
{
socket->state = IP_PING;
ptrSend[IP_PROTOCOL] = 0x01; //PING
memset(ptrSend+PING_TYPE, 0, 8);
ptrSend[PING_TYPE] = 8; //SEND
}
//Add socket to linked list
OS_MutexPend(IPMutex);
socket->next = SocketHead;
socket->prev = NULL;
if(SocketHead)
SocketHead->prev = socket;
SocketHead = socket;
OS_MutexPost(IPMutex);
if(mode == IP_MODE_TCP && ipAddress)
{
//Send TCP SYN
socket->seq = 0x01234567;
frame = IPFrameGet(0);
if(frame)
{
frame->packet[TCP_FLAGS] = TCP_FLAGS_SYN;
frame->packet[TCP_DATA] = 2; //maximum segment size = 536
frame->packet[TCP_DATA+1] = 4;
frame->packet[TCP_DATA+2] = 2;
frame->packet[TCP_DATA+3] = 24;
TCPSendPacket(socket, frame, TCP_DATA+4);
++socket->seq;
}
}
return socket;
}
void IPWriteFlush(IPSocket *socket)
{
uint8 *packetOut;
if(socket->frameSend && socket->state != IP_UDP &&
socket->state != IP_PING)
{
packetOut = socket->frameSend->packet;
packetOut[TCP_FLAGS] = TCP_FLAGS_ACK | TCP_FLAGS_PSH;
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, tries=0;
int offset;
OS_Thread_t *self;
if(socket->timeout)
socket->timeout = socket->timeoutReset;
#ifdef INCLUDE_FILESYS
if(socket->fileOut) //override stdout
return fwrite((char*)buf, 1, length, socket->fileOut);
#endif
//printf("IPWrite(0x%x, %d)", Socket, Length);
self = OS_ThreadSelf();
while(length)
{
//Rate limit output
if(socket->seq - socket->seqReceived >= SEND_WINDOW)
{
//printf("l(%d,%d,%d) ", socket->seq - socket->seqReceived, socket->seq, socket->seqReceived);
if(self != IPThread && ++tries < 200)
{
OS_ThreadSleep(1);
continue;
}
}
tries = 0;
while(socket->frameSend == NULL)
{
socket->frameSend = IPFrameGet(FRAME_COUNT_SEND);
socket->sendOffset = 0;
if(socket->frameSend == NULL)
{
//printf("L");
if(self == IPThread || ++tries > 200)
break;
else
OS_ThreadSleep(1);
}
}
frameOut = socket->frameSend;
offset = socket->sendOffset;
if(frameOut == NULL)
break;
packetOut = frameOut->packet;
if(socket->state == IP_PING)
{
bytes = length;
memcpy(packetOut, socket->headerSend, PING_DATA);
memcpy(packetOut+PING_DATA, buf, bytes);
IPSendPacket(socket, socket->frameSend, PING_DATA + bytes);
socket->frameSend = NULL;
}
else if(socket->state != IP_UDP)
{
bytes = 512 - offset;
if(bytes > length)
bytes = length;
socket->sendOffset += bytes;
memcpy(packetOut+TCP_DATA+offset, buf, bytes);
if(socket->sendOffset >= 512)
IPWriteFlush(socket);
//if(Socket->seq - Socket->seqReceived > Socket->seqWindow)
//{
// printf("W");
// OS_ThreadSleep(10);
//}
}
else //UDP
{
bytes = length;
memcpy(packetOut+UDP_DATA+offset, buf, bytes);
memcpy(packetOut, socket->headerSend, UDP_LENGTH);
IPSendPacket(socket, socket->frameSend, UDP_DATA + bytes);
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;
#ifdef INCLUDE_FILESYS
if(socket->fileIn) //override stdin
{
bytes = fread(buf, 1, 1, socket->fileIn);
if(bytes == 0)
{
buf[0] = 0;
fclose(socket->fileIn);
socket->fileIn = NULL;
bytes = 1;
}
return bytes;
}
#endif
if(socket->state == IP_UDP)
offset = UDP_DATA;
else
offset = TCP_DATA;
OS_MutexPend(IPMutex);
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);
socket->ackProcessed += frame2->length - offset;
if(socket->state == IP_TCP &&
socket->ack - socket->ackProcessed > RECEIVE_WINDOW - 2048)
{
//Update receive window for flow control
frame2->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
TCPSendPacket(socket, frame2, TCP_DATA);
}
else
FrameFree(frame2);
}
}
OS_MutexPost(IPMutex);
return count;
}
static void IPClose2(IPSocket *socket)
{
IPFrame *frame, *framePrev;
OS_MutexPend(IPMutex);
//Mark packets as don't retransmit
for(frame = FrameSendHead; frame; frame = frame->next)
{
if(frame->socket == socket)
frame->socket = NULL;
}
//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->state == IP_CLOSED || socket->state <= IP_UDP)
{
if(socket->prev == NULL)
SocketHead = socket->next;
else
socket->prev->next = socket->next;
if(socket->next)
socket->next->prev = socket->prev;
free(socket);
}
else
{
//Give application 10 seconds to stop using socket
if(socket->state > IP_UDP)
socket->state = IP_CLOSED;
socket->timeout = 10;
}
OS_MutexPost(IPMutex);
}
void IPClose(IPSocket *socket)
{
IPFrame *frameOut;
IPWriteFlush(socket);
if(socket->state <= IP_UDP)
{
IPClose2(socket);
return;
}
frameOut = IPFrameGet(0);
if(frameOut == NULL)
return;
frameOut->packet[TCP_FLAGS] = TCP_FLAGS_FIN | TCP_FLAGS_ACK;
TCPSendPacket(socket, frameOut, TCP_DATA);
++socket->seq;
if(socket->state == IP_FIN_CLIENT)
IPClose2(socket);
else
socket->state = IP_FIN_SERVER;
}
void IPPrintf(IPSocket *socket, char *message,
int arg0, int arg1, int arg2, int arg3)
{
char buf[500];
if(socket == NULL)
{
printf(message, arg0, arg1, arg2, arg3);
return;
}
if(strcmp(message, "%s") == 0)
IPWrite(socket, (uint8*)arg0, (int)strlen((char*)arg0));
else
{
sprintf(buf, message, arg0, arg1, arg2, arg3, 0, 0, 0, 0);
IPWrite(socket, (uint8*)buf, (int)strlen(buf));
}
if(socket->dontFlush == 0 || strstr(message, "\n"))
IPWriteFlush(socket);
}
void IPTick(void)
{
IPFrame *frame, *frame2;
IPSocket *socket, *socket2;
unsigned long ticks;
static unsigned long ticksPrev=0, ticksPrev2=0;
ticks = OS_ThreadTime();
#ifdef WIN32
ticks = ticksPrev + 100;
#endif
if(ticks - ticksPrev >= 95)
{
if(IPVerbose && (Seconds % 60) == 0)
{
if(FrameFreeCount >= FRAME_COUNT-1)
printf("T");
else
printf("T(%d)", FrameFreeCount);
}
++Seconds;
if(--DhcpRetrySeconds <= 0)
IPDhcp(NULL, 400, 1); //DHCP request
}
OS_MutexPend(IPMutex);
//Retransmit timeout packets
for(frame = FrameResendHead; frame; )
{
frame2 = frame;
frame = frame->next;
frame2->timeout = (short)(frame2->timeout - (ticks - ticksPrev2));
if(--frame2->timeout <= 0)
{
if(IPVerbose)
printf("r");
FrameRemove(&FrameResendHead, &FrameResendTail, frame2);
IPSendFrame(frame2);
}
}
if(ticks - ticksPrev >= 95)
{
//Close timed out sockets
for(socket = SocketHead; socket; )
{
socket2 = socket;
socket = socket->next;
if(socket2->timeout && --socket2->timeout == 0)
{
socket2->timeout = 10;
if(IPVerbose && socket2->state != IP_CLOSED &&
socket2->state != IP_FIN_SERVER)
printf("t(%d,%d)", socket2->state, FrameFreeCount);
if(socket2->state == IP_TCP)
IPClose(socket2);
else if(socket2->state == IP_FIN_CLIENT)
IPClose(socket2);
else
IPClose2(socket2);
}
}
ticksPrev = ticks;
}
OS_MutexPost(IPMutex);
ticksPrev2 = ticks;
}
static void DnsCallback(IPSocket *socket)
{
uint8 buf[200], *ptr;
uint32 ipAddress;
int bytes;
memset(buf, 0, sizeof(buf));
bytes = IPRead(socket, buf, sizeof(buf));
if(buf[DNS_NUM_ANSWERS_RR+1])
{
for(ptr = buf + DNS_QUESTIONS; ptr + 14 <= buf + bytes; ++ptr)
{
if(ptr[0] == 0 && ptr[1] == 1 && ptr[2] == 0 && ptr[3] == 1 &&
ptr[8] == 0 && ptr[9] == 4)
{
ipAddress = (ptr[10] << 24) | (ptr[11] << 16) | (ptr[12] << 8) | ptr[13];
printf("ipAddress = %d.%d.%d.%d\n", ptr[10], ptr[11], ptr[12], ptr[13]);
socket->userData = ipAddress;
if(socket->userFunc)
{
socket->userFunc(socket, ipAddress, socket->userPtr);
}
break;
}
}
}
IPClose(socket);
}
void IPResolve(char *name, IPFuncPtr resolvedFunc, void *arg)
{
uint8 buf[200], *ptr;
int length, i;
IPSocket *socket;
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->userPtr = arg;
socket->userData = 0;
IPWrite(socket, buf, length);
}