URL
https://opencores.org/ocsvn/plasma/plasma/trunk
Subversion Repositories plasma
[/] [plasma/] [trunk/] [kernel/] [tcpip.c] - Rev 358
Go to most recent revision | Compare with Previous | Blame | View Log
/*-------------------------------------------------------------------- * 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); //if(rc) //{ // printf("C "); // return; //} //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(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, frame->length); 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_MutexPend(IPMutex); frameOut = FrameSendTail; if(frameOut) FrameRemove(&FrameSendHead, &FrameSendTail, frameOut); OS_MutexPost(IPMutex); if(frameOut) { Led(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; //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; 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); }
Go to most recent revision | Compare with Previous | Blame | View Log