📄 tcpip.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"#include "tcpip.h"#ifdef WIN32#undef OS_CriticalBegin#undef OS_CriticalEnd#define OS_CriticalBegin() 0#define OS_CriticalEnd(A)#define OS_ThreadCreate(A,B,C,D,E) 0#define OS_ThreadSleep(A)#define OS_ThreadTime() 0#define OS_ThreadSelf() 0#define OS_MutexCreate(A) NULL#define OS_MutexPend(A)#define OS_MutexPost(A)#define OS_MQueueCreate(A,B,C) 0#define OS_MQueueSend(A,B) 0#define OS_MQueueGet(A,B,C) 0#define UartPacketConfig(A,B,C)#define UartPacketSend(A,B)#define UartPrintf printf#define UartPrintfCritical printf#define Led(A)#endif//ETHER FIELD OFFSET LENGTH VALUE#define ETHERNET_DEST 0 //6#define ETHERNET_SOURCE 6 //6#define ETHERNET_FRAME_TYPE 12 //2 IP=0x0800; ARP=0x0806//ARP FIELD OFFSET LENGTH VALUE#define ARP_HARD_TYPE 14 //2 0x0001#define ARP_PROT_TYPE 16 //2 0x0800#define ARP_HARD_SIZE 18 //1 0x06#define ARP_PROT_SIZE 19 //1 0x04#define ARP_OP 20 //2 ARP=1;ARPreply=2#define ARP_ETHERNET_SENDER 22 //6#define ARP_IP_SENDER 28 //4#define ARP_ETHERNET_TARGET 32 //6#define ARP_IP_TARGET 38 //4#define ARP_PAD 42 //18 0//IP FIELD OFFSET LENGTH VALUE#define IP_VERSION_LENGTH 14 //1 0x45#define IP_TYPE_OF_SERVICE 15 //1 0x00#define IP_LENGTH 16 //2#define IP_ID16 18 //2#define IP_FRAG_OFFSET 20 //2#define IP_TIME_TO_LIVE 22 //1 0x80#define IP_PROTOCOL 23 //1 TCP=0x06;PING=0x01;UDP=0x11#define IP_CHECKSUM 24 //2#define IP_SOURCE 26 //4#define IP_DEST 30 //4//PSEUDO FIELD OFFSET LENGTH VALUE#define PSEUDO_IP_SOURCE 0 //4#define PSEUDO_IP_DEST 4 //4#define PSEUDO_ZERO 8 //1 0#define PSEUDO_IP_PROTOCOL 9 //1#define PSEUDO_LENGTH 10 //2//UDP FIELD OFFSET LENGTH VALUE#define UDP_SOURCE_PORT 34 //2#define UDP_DEST_PORT 36 //2#define UDP_LENGTH 38 //2#define UDP_CHECKSUM 40 //2#define UDP_DATA 42//DHCP FIELD OFFSET LENGTH VALUE#define DHCP_OPCODE 42 //1 REQUEST=1;REPLY=2#define DHCP_HW_TYPE 43 //1 1#define DHCP_HW_LEN 44 //1 6#define DHCP_HOP_COUNT 45 //1 0#define DHCP_TRANS_ID 46 //4#define DHCP_NUM_SEC 50 //2 0#define DHCP_UNUSED 52 //2#define DHCP_CLIENT_IP 54 //4#define DHCP_YOUR_IP 58 //4#define DHCP_SERVER_IP 62 //4#define DHCP_GATEWAY_IP 66 //4#define DHCP_CLIENT_ETHERNET 70 //16#define DHCP_SERVER_NAME 86 //64#define DHCP_BOOT_FILENAME 150 //128#define DHCP_MAGIC_COOKIE 278 //4 0x63825363#define DHCP_OPTIONS 282 //N#define DHCP_MESSAGE_TYPE 53 //1 type#define DHCP_DISCOVER 1#define DHCP_OFFER 2#define DHCP_REQUEST 3#define DHCP_ACK 5#define DHCP_REQUEST_IP 50 //4 ip#define DHCP_REQUEST_SERV_IP 54 //4 ip#define DHCP_CLIENT_ID 61 //7 1 ethernet#define DHCP_HOST_NAME 12 //6 plasma#define DHCP_PARAMS 55 //4 1=subnet; 15=domain_name; 3=router; 6=dns#define DHCP_PARAM_SUBNET 1#define DHCP_PARAM_ROUTER 3#define DHCP_PARAM_DNS 6#define DHCP_END_OPTION 0xff//DHCP FIELD OFFSET LENGTH VALUE#define DNS_ID 0 //2 #define DNS_FLAGS 2 //2 #define DNS_NUM_QUESTIONS 4 //2 1 #define DNS_NUM_ANSWERS_RR 6 //2 0/1#define DNS_NUM_AUTHORITY_RR 8 //2 0 #define DNS_NUM_ADDITIONAL_RR 10 //2 0#define DNS_QUESTIONS 12 //2 #define DNS_FLAGS_RESPONSE 0x8000#define DNS_FLAGS_RECURSIVE 0x0100#define DNS_FLAGS_ERROR 0x0003#define DNS_FLAGS_OK 0x0000#define DNS_QUERY_TYPE_IP 1#define DNS_QUERY_CLASS 1#define DNS_PORT 53//TCP FIELD OFFSET LENGTH VALUE#define TCP_SOURCE_PORT 34 //2#define TCP_DEST_PORT 36 //2#define TCP_SEQ 38 //4#define TCP_ACK 42 //4#define TCP_HEADER_LENGTH 46 //1 0x50#define TCP_FLAGS 47 //1 SYNC=0x2;ACK=0x10;FIN=0x1#define TCP_WINDOW_SIZE 48 //2#define TCP_CHECKSUM 50 //2#define TCP_URGENT_POINTER 52 //2#define TCP_DATA 54 //length-N#define TCP_FLAGS_FIN 1#define TCP_FLAGS_SYN 2#define TCP_FLAGS_RST 4#define TCP_FLAGS_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 44static void IPClose2(IPSocket *Socket);static uint8 ethernetAddressNull[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};static uint8 ethernetAddressGateway[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};#ifndef WIN32static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4};#elsestatic uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd5};#endifstatic uint8 ipAddressPlasma[] = {0x9d, 0xfe, 0x28, 10}; //changed by DHCPstatic uint8 ipAddressGateway[] = {0xff, 0xff, 0xff, 0xff}; //changed by DHCPstatic uint32 ipAddressDns; //changed by DHCPstatic OS_Mutex_t *IPMutex;static int FrameFreeCount=FRAME_COUNT;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 const unsigned char dhcpOptions[] = { 0x63, 0x82, 0x53, 0x63, //cookie 0x35, 0x01, 0x01, //DHCP Discover 0x3d, 0x07, 0x01, 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //Client identifier#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 ISRIPFrame *IPFrameGet(int freeCount){ IPFrame *frame=NULL; uint32 state; state = OS_CriticalBegin(); if(FrameFreeCount > freeCount) { --FrameFreeCount; frame = FrameFreeHead; if(FrameFreeHead) FrameFreeHead = FrameFreeHead->next; } 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 } else { //Put on resend list until TCP ACK'ed frame->timeout = RETRANSMIT_TIME; FrameInsert(&FrameResendHead, &FrameResendTail, frame); }}static void IPSendFrame(IPFrame *frame){ uint32 message[4]; if(FrameSendFunc) { //Single threaded FrameSendFunc(frame->packet, frame->length); IPFrameReschedule(frame); } else { //Add Packet to send queue FrameInsert(&FrameSendHead, &FrameSendTail, frame);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -