mirror of
git://projects.qi-hardware.com/nn-usb-fpga.git
synced 2024-12-13 06:33:09 +02:00
1680 lines
52 KiB
C
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);
|
|
}
|
|
|