1 /*--------------------------------------------------------------------
\r
2 * TITLE: Plasma TCP/IP Protocol Stack
\r
3 * AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
\r
4 * DATE CREATED: 4/22/06
\r
6 * PROJECT: Plasma CPU core
\r
7 * COPYRIGHT: Software placed into the public domain by the author.
\r
8 * Software 'as is' without warranty. Author liable for nothing.
\r
10 * Plasma TCP/IP Protocol Stack
\r
12 * Possible call stack when receiving a packet:
\r
14 * IPProcessEthernetPacket()
\r
15 * IPProcessTCPPacket()
\r
21 *--------------------------------------------------------------------*/
\r
34 //ETHER FIELD OFFSET LENGTH VALUE
\r
35 #define ETHERNET_DEST 0 //6
\r
36 #define ETHERNET_SOURCE 6 //6
\r
37 #define ETHERNET_FRAME_TYPE 12 //2 IP=0x0800; ARP=0x0806
\r
39 //ARP FIELD OFFSET LENGTH VALUE
\r
40 #define ARP_HARD_TYPE 14 //2 0x0001
\r
41 #define ARP_PROT_TYPE 16 //2 0x0800
\r
42 #define ARP_HARD_SIZE 18 //1 0x06
\r
43 #define ARP_PROT_SIZE 19 //1 0x04
\r
44 #define ARP_OP 20 //2 ARP=1;ARPreply=2
\r
45 #define ARP_ETHERNET_SENDER 22 //6
\r
46 #define ARP_IP_SENDER 28 //4
\r
47 #define ARP_ETHERNET_TARGET 32 //6
\r
48 #define ARP_IP_TARGET 38 //4
\r
49 #define ARP_PAD 42 //18 0
\r
51 //IP FIELD OFFSET LENGTH VALUE
\r
52 #define IP_VERSION_LENGTH 14 //1 0x45
\r
53 #define IP_TYPE_OF_SERVICE 15 //1 0x00
\r
54 #define IP_LENGTH 16 //2
\r
55 #define IP_ID16 18 //2
\r
56 #define IP_FRAG_OFFSET 20 //2
\r
57 #define IP_TIME_TO_LIVE 22 //1 0x80
\r
58 #define IP_PROTOCOL 23 //1 TCP=0x06;PING=0x01;UDP=0x11
\r
59 #define IP_CHECKSUM 24 //2
\r
60 #define IP_SOURCE 26 //4
\r
61 #define IP_DEST 30 //4
\r
63 //PSEUDO FIELD OFFSET LENGTH VALUE
\r
64 #define PSEUDO_IP_SOURCE 0 //4
\r
65 #define PSEUDO_IP_DEST 4 //4
\r
66 #define PSEUDO_ZERO 8 //1 0
\r
67 #define PSEUDO_IP_PROTOCOL 9 //1
\r
68 #define PSEUDO_LENGTH 10 //2
\r
70 //UDP FIELD OFFSET LENGTH VALUE
\r
71 #define UDP_SOURCE_PORT 34 //2
\r
72 #define UDP_DEST_PORT 36 //2
\r
73 #define UDP_LENGTH 38 //2
\r
74 #define UDP_CHECKSUM 40 //2
\r
77 //DHCP FIELD OFFSET LENGTH VALUE
\r
78 #define DHCP_OPCODE 42 //1 REQUEST=1;REPLY=2
\r
79 #define DHCP_HW_TYPE 43 //1 1
\r
80 #define DHCP_HW_LEN 44 //1 6
\r
81 #define DHCP_HOP_COUNT 45 //1 0
\r
82 #define DHCP_TRANS_ID 46 //4
\r
83 #define DHCP_NUM_SEC 50 //2 0
\r
84 #define DHCP_UNUSED 52 //2
\r
85 #define DHCP_CLIENT_IP 54 //4
\r
86 #define DHCP_YOUR_IP 58 //4
\r
87 #define DHCP_SERVER_IP 62 //4
\r
88 #define DHCP_GATEWAY_IP 66 //4
\r
89 #define DHCP_CLIENT_ETHERNET 70 //16
\r
90 #define DHCP_SERVER_NAME 86 //64
\r
91 #define DHCP_BOOT_FILENAME 150 //128
\r
92 #define DHCP_MAGIC_COOKIE 278 //4 0x63825363
\r
93 #define DHCP_OPTIONS 282 //N
\r
95 #define DHCP_MESSAGE_TYPE 53 //1 type
\r
96 #define DHCP_DISCOVER 1
\r
97 #define DHCP_OFFER 2
\r
98 #define DHCP_REQUEST 3
\r
100 #define DHCP_REQUEST_IP 50 //4 ip
\r
101 #define DHCP_REQUEST_SERV_IP 54 //4 ip
\r
102 #define DHCP_CLIENT_ID 61 //7 1 ethernet
\r
103 #define DHCP_HOST_NAME 12 //6 plasma
\r
104 #define DHCP_PARAMS 55 //4 1=subnet; 15=domain_name; 3=router; 6=dns
\r
105 #define DHCP_PARAM_SUBNET 1
\r
106 #define DHCP_PARAM_ROUTER 3
\r
107 #define DHCP_PARAM_DNS 6
\r
108 #define DHCP_END_OPTION 0xff
\r
110 //DHCP FIELD OFFSET LENGTH VALUE
\r
111 #define DNS_ID 0 //2
\r
112 #define DNS_FLAGS 2 //2
\r
113 #define DNS_NUM_QUESTIONS 4 //2 1
\r
114 #define DNS_NUM_ANSWERS_RR 6 //2 0/1
\r
115 #define DNS_NUM_AUTHORITY_RR 8 //2 0
\r
116 #define DNS_NUM_ADDITIONAL_RR 10 //2 0
\r
117 #define DNS_QUESTIONS 12 //2
\r
119 #define DNS_FLAGS_RESPONSE 0x8000
\r
120 #define DNS_FLAGS_RECURSIVE 0x0100
\r
121 #define DNS_FLAGS_ERROR 0x0003
\r
122 #define DNS_FLAGS_OK 0x0000
\r
123 #define DNS_QUERY_TYPE_IP 1
\r
124 #define DNS_QUERY_CLASS 1
\r
125 #define DNS_PORT 53
\r
127 //TCP FIELD OFFSET LENGTH VALUE
\r
128 #define TCP_SOURCE_PORT 34 //2
\r
129 #define TCP_DEST_PORT 36 //2
\r
130 #define TCP_SEQ 38 //4
\r
131 #define TCP_ACK 42 //4
\r
132 #define TCP_HEADER_LENGTH 46 //1 0x50
\r
133 #define TCP_FLAGS 47 //1 SYNC=0x2;ACK=0x10;FIN=0x1
\r
134 #define TCP_WINDOW_SIZE 48 //2
\r
135 #define TCP_CHECKSUM 50 //2
\r
136 #define TCP_URGENT_POINTER 52 //2
\r
137 #define TCP_DATA 54 //length-N
\r
139 #define TCP_FLAGS_FIN 1
\r
140 #define TCP_FLAGS_SYN 2
\r
141 #define TCP_FLAGS_RST 4
\r
142 #define TCP_FLAGS_PSH 8
\r
143 #define TCP_FLAGS_ACK 16
\r
145 //PING FIELD OFFSET LENGTH VALUE
\r
146 #define PING_TYPE 34 //1 SEND=8;REPLY=0
\r
147 #define PING_CODE 35 //1 0
\r
148 #define PING_CHECKSUM 36 //2
\r
149 #define PING_ID 38 //2
\r
150 #define PING_SEQUENCE 40 //2
\r
151 #define PING_DATA 44
\r
153 static void IPClose2(IPSocket *Socket);
\r
154 static void IPArp(unsigned char ipAddress[4]);
\r
156 typedef struct ArpCache_s {
\r
157 unsigned char ip[4];
\r
158 unsigned char mac[6];
\r
160 static ArpCache_t ArpCache[10];
\r
161 static int ArpCacheIndex;
\r
163 static uint8 ethernetAddressGateway[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
\r
165 static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4};
\r
167 static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd5};
\r
170 static uint8 ipAddressPlasma[] = {192, 168, 100, 10}; //changed by DHCP
\r
171 static uint8 ipAddressGateway[] = {0x00, 0x00, 0x00, 0x00}; //changed by DHCP
\r
172 static uint32 ipAddressDns; //changed by DHCP
\r
174 static OS_Mutex_t *IPMutex;
\r
175 static int FrameFreeCount;
\r
176 static IPFrame *FrameFreeHead;
\r
177 static IPFrame *FrameSendHead;
\r
178 static IPFrame *FrameSendTail;
\r
179 static IPFrame *FrameResendHead;
\r
180 static IPFrame *FrameResendTail;
\r
181 static IPSocket *SocketHead;
\r
182 static uint32 Seconds;
\r
183 static int DhcpRetrySeconds;
\r
184 static IPFuncPtr FrameSendFunc;
\r
185 static OS_MQueue_t *IPMQueue;
\r
186 static OS_Thread_t *IPThread;
\r
189 static const unsigned char dhcpDiscover[] = {
\r
190 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dest
\r
191 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //src
\r
193 0x45, 0x00, 0x01, 0x48, 0x2e, 0xf5, 0x00, 0x00, //ip
\r
194 0x80, 0x11, 0x0a, 0xb1, 0x00, 0x00, 0x00, 0x00,
\r
195 0xff, 0xff, 0xff, 0xff,
\r
196 0x00, 0x44, 0x00, 0x43, 0x01, 0x34, 0x45, 0x66, //udp
\r
197 0x01, 0x01, 0x06, 0x00, 0x69, 0x26, 0xb5, 0x52 //dhcp
\r
200 static unsigned char dhcpOptions[] = {
\r
201 0x63, 0x82, 0x53, 0x63, //cookie
\r
202 0x35, 0x01, 0x01, //DHCP Discover
\r
203 0x3d, 0x07, 0x01, 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //Client identifier
\r
205 0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'a', //Host name
\r
207 0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'b', //Host name
\r
209 0x37, 0x03, DHCP_PARAM_SUBNET, DHCP_PARAM_ROUTER, DHCP_PARAM_DNS, //Parameters
\r
214 //Get a free frame; can be called from an ISR
\r
215 IPFrame *IPFrameGet(int freeCount)
\r
217 IPFrame *frame=NULL;
\r
220 state = OS_CriticalBegin();
\r
221 if(FrameFreeCount > freeCount)
\r
223 frame = FrameFreeHead;
\r
226 FrameFreeHead = FrameFreeHead->next;
\r
230 OS_CriticalEnd(state);
\r
233 assert(frame->state == 0);
\r
240 static void FrameFree(IPFrame *frame)
\r
244 assert(frame->state == 1);
\r
246 state = OS_CriticalBegin();
\r
247 frame->next = FrameFreeHead;
\r
248 FrameFreeHead = frame;
\r
250 OS_CriticalEnd(state);
\r
254 static void FrameInsert(IPFrame **head, IPFrame **tail, IPFrame *frame)
\r
256 assert(frame->state == 1);
\r
258 OS_MutexPend(IPMutex);
\r
259 frame->prev = NULL;
\r
260 frame->next = *head;
\r
262 (*head)->prev = frame;
\r
266 OS_MutexPost(IPMutex);
\r
270 static void FrameRemove(IPFrame **head, IPFrame **tail, IPFrame *frame)
\r
272 assert(frame->state == 2);
\r
273 if(frame->state != 2)
\r
275 printf("frame->state=%d\n", frame->state);
\r
280 frame->prev->next = frame->next;
\r
282 *head = frame->next;
\r
284 frame->next->prev = frame->prev;
\r
286 *tail = frame->prev;
\r
287 frame->prev = NULL;
\r
288 frame->next = NULL;
\r
292 static int IPChecksum(int checksum, const unsigned char *data, int length)
\r
295 checksum = ~checksum & 0xffff;
\r
296 for(i = 0; i < length-1; i += 2)
\r
298 checksum += (data[i] << 8) | data[i+1];
\r
301 checksum += data[i] << 8;
\r
302 while(checksum >> 16)
\r
303 checksum = (checksum & 0xffff) + (checksum >> 16);
\r
304 checksum = ~checksum & 0xffff;
\r
309 static int EthernetVerifyChecksums(const unsigned char *packet, int length)
\r
311 int checksum, length2;
\r
312 unsigned char pseudo[12];
\r
314 //Calculate checksums
\r
315 if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP
\r
317 checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20);
\r
320 if(packet[IP_PROTOCOL] == 0x01) //PING
\r
322 checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE);
\r
324 else if(packet[IP_PROTOCOL] == 0x11) //UDP
\r
326 if(packet[UDP_CHECKSUM] == 0 && packet[UDP_CHECKSUM+1] == 0)
\r
328 memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
\r
329 memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
\r
330 pseudo[PSEUDO_ZERO] = 0;
\r
331 pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
\r
332 memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2);
\r
333 checksum = IPChecksum(0xffff, pseudo, 12);
\r
334 length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1];
\r
335 checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length);
\r
337 else if(packet[IP_PROTOCOL] == 0x06) //TCP
\r
339 memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
\r
340 memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
\r
341 pseudo[PSEUDO_ZERO] = 0;
\r
342 pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
\r
343 length = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1];
\r
344 length2 = length - 20;
\r
345 pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8);
\r
346 pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2;
\r
347 checksum = IPChecksum(0xffff, pseudo, 12);
\r
348 checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2);
\r
357 static void IPFrameReschedule(IPFrame *frame)
\r
360 length = frame->length - TCP_DATA;
\r
361 if(frame->packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN))
\r
363 if(frame->socket == NULL || frame->socket->state == IP_UDP || length == 0 ||
\r
364 frame->socket->state == IP_PING || ++frame->retryCnt > 4)
\r
366 FrameFree(frame); //can't be ACK'ed
\r
369 else if(FrameFreeCount < FRAME_COUNT_SYNC)
\r
371 FrameFree(frame); //can't be ACK'ed
\r
376 //Put on resend list until TCP ACK'ed
\r
377 frame->timeout = (short)(RETRANSMIT_TIME * frame->retryCnt);
\r
378 FrameInsert(&FrameResendHead, &FrameResendTail, frame);
\r
383 static void IPSendFrame(IPFrame *frame)
\r
387 unsigned char *packet=frame->packet;
\r
389 //Check if MAC address unknown
\r
390 if(packet[ETHERNET_FRAME_TYPE+1] == 0x00 && //IP
\r
391 packet[ETHERNET_DEST] == 0xff && packet[IP_DEST] != 0xff)
\r
393 for(i = 0; i < sizeof(ArpCache) / sizeof(ArpCache_t); ++i)
\r
395 if(memcmp(packet+IP_DEST, ArpCache[i].ip, 4) == 0)
\r
397 memcpy(packet+ETHERNET_DEST, ArpCache[i].mac, 6);
\r
399 memcpy(frame->socket->headerSend+ETHERNET_DEST, ArpCache[i].mac, 6);
\r
403 if(packet[ETHERNET_DEST] == 0xff)
\r
404 IPArp(packet+IP_DEST);
\r
410 FrameSendFunc(frame->packet, frame->length);
\r
411 IPFrameReschedule(frame);
\r
415 //Add Packet to send queue
\r
416 FrameInsert(&FrameSendHead, &FrameSendTail, frame);
\r
418 //Wakeup sender thread
\r
420 OS_MQueueSend(IPMQueue, message);
\r
425 static void IPSendPacket(IPSocket *socket, IPFrame *frame, int length)
\r
427 int checksum, length2=length;
\r
428 unsigned char pseudo[12], *packet=frame->packet;
\r
430 frame->length = (uint16)length;
\r
432 //Calculate checksums
\r
433 if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP
\r
435 length2 = length - IP_VERSION_LENGTH;
\r
436 packet[IP_LENGTH] = (uint8)(length2 >> 8);
\r
437 packet[IP_LENGTH+1] = (uint8)length2;
\r
438 memset(packet+IP_CHECKSUM, 0, 2);
\r
439 checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20);
\r
440 packet[IP_CHECKSUM] = (unsigned char)(checksum >> 8);
\r
441 packet[IP_CHECKSUM+1] = (unsigned char)checksum;
\r
442 if(packet[IP_PROTOCOL] == 0x01) //ICMP & PING
\r
444 memset(packet+PING_CHECKSUM, 0, 2);
\r
445 checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE);
\r
446 packet[PING_CHECKSUM] = (unsigned char)(checksum >> 8);
\r
447 packet[PING_CHECKSUM+1] = (unsigned char)checksum;
\r
449 else if(packet[IP_PROTOCOL] == 0x11) //UDP
\r
451 length2 = length - UDP_SOURCE_PORT;
\r
452 packet[UDP_LENGTH] = (uint8)(length2 >> 8);
\r
453 packet[UDP_LENGTH+1] = (uint8)length2;
\r
454 memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
\r
455 memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
\r
456 pseudo[PSEUDO_ZERO] = 0;
\r
457 pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
\r
458 memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2);
\r
459 checksum = IPChecksum(0xffff, pseudo, 12);
\r
460 memset(packet+UDP_CHECKSUM, 0, 2);
\r
461 length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1];
\r
462 checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length2);
\r
463 packet[UDP_CHECKSUM] = (unsigned char)(checksum >> 8);
\r
464 packet[UDP_CHECKSUM+1] = (unsigned char)checksum;
\r
466 else if(packet[IP_PROTOCOL] == 0x06) //TCP
\r
468 memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4);
\r
469 memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4);
\r
470 pseudo[PSEUDO_ZERO] = 0;
\r
471 pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL];
\r
472 length2 = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1];
\r
473 length2 = length2 - 20;
\r
474 pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8);
\r
475 pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2;
\r
476 checksum = IPChecksum(0xffff, pseudo, 12);
\r
477 memset(packet+TCP_CHECKSUM, 0, 2);
\r
478 checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2);
\r
479 packet[TCP_CHECKSUM] = (unsigned char)(checksum >> 8);
\r
480 packet[TCP_CHECKSUM+1] = (unsigned char)checksum;
\r
484 length2 = length - TCP_DATA;
\r
485 if(socket && (packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN)))
\r
487 frame->socket = socket;
\r
488 frame->timeout = 0;
\r
489 frame->retryCnt = 0;
\r
491 frame->seqEnd = socket->seq + length2;
\r
492 IPSendFrame(frame);
\r
496 static void TCPSendPacket(IPSocket *socket, IPFrame *frame, int length)
\r
498 uint8 *packet = frame->packet;
\r
501 flags = packet[TCP_FLAGS];
\r
502 memcpy(packet, socket->headerSend, TCP_SEQ);
\r
503 packet[TCP_FLAGS] = (uint8)flags;
\r
504 if(flags & TCP_FLAGS_SYN)
\r
505 packet[TCP_HEADER_LENGTH] = 0x60; //set maximum segment size
\r
507 packet[TCP_HEADER_LENGTH] = 0x50;
\r
508 packet[TCP_SEQ] = (uint8)(socket->seq >> 24);
\r
509 packet[TCP_SEQ+1] = (uint8)(socket->seq >> 16);
\r
510 packet[TCP_SEQ+2] = (uint8)(socket->seq >> 8);
\r
511 packet[TCP_SEQ+3] = (uint8)socket->seq;
\r
512 packet[TCP_ACK] = (uint8)(socket->ack >> 24);
\r
513 packet[TCP_ACK+1] = (uint8)(socket->ack >> 16);
\r
514 packet[TCP_ACK+2] = (uint8)(socket->ack >> 8);
\r
515 packet[TCP_ACK+3] = (uint8)socket->ack;
\r
516 count = RECEIVE_WINDOW - (socket->ack - socket->ackProcessed);
\r
519 packet[TCP_WINDOW_SIZE] = (uint8)(count >> 8);
\r
520 packet[TCP_WINDOW_SIZE+1] = (uint8)count;
\r
521 packet[TCP_URGENT_POINTER] = 0;
\r
522 packet[TCP_URGENT_POINTER+1] = 0;
\r
523 IPSendPacket(socket, frame, length);
\r
527 static void EthernetCreateResponse(unsigned char *packetOut,
\r
528 const unsigned char *packet,
\r
531 //Swap destination and source fields
\r
532 memcpy(packetOut, packet, length);
\r
533 memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6);
\r
534 memcpy(packetOut+ETHERNET_SOURCE, packet+ETHERNET_DEST, 6);
\r
535 if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP
\r
537 memcpy(packetOut+IP_SOURCE, packet+IP_DEST, 4);
\r
538 memcpy(packetOut+IP_DEST, packet+IP_SOURCE, 4);
\r
539 if(packet[IP_PROTOCOL] == 0x06 || packet[IP_PROTOCOL] == 0x11) //TCP/UDP
\r
541 memcpy(packetOut+TCP_SOURCE_PORT, packet+TCP_DEST_PORT, 2);
\r
542 memcpy(packetOut+TCP_DEST_PORT, packet+TCP_SOURCE_PORT, 2);
\r
548 static void IPArp(unsigned char ipAddress[4])
\r
553 frame = IPFrameGet(0);
\r
556 packetOut = frame->packet;
\r
557 memset(packetOut, 0, 512);
\r
558 memset(packetOut+ETHERNET_DEST, 0xff, 6);
\r
559 memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
\r
560 packetOut[ETHERNET_FRAME_TYPE] = 0x08;
\r
561 packetOut[ETHERNET_FRAME_TYPE+1] = 0x06;
\r
562 packetOut[ARP_HARD_TYPE+1] = 0x01;
\r
563 packetOut[ARP_PROT_TYPE] = 0x08;
\r
564 packetOut[ARP_HARD_SIZE] = 0x06;
\r
565 packetOut[ARP_PROT_SIZE] = 0x04;
\r
566 packetOut[ARP_OP+1] = 1;
\r
567 memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6);
\r
568 memcpy(packetOut+ARP_IP_SENDER, ipAddressPlasma, 4);
\r
569 memcpy(packetOut+ARP_IP_TARGET, ipAddress, 4);
\r
570 IPSendPacket(NULL, frame, 60);
\r
574 static void IPDhcp(const unsigned char *packet, int length, int state)
\r
576 uint8 *packetOut, *ptr;
\r
579 static int request=0;
\r
583 //Create DHCP Discover
\r
584 frame = IPFrameGet(0);
\r
587 packetOut = frame->packet;
\r
588 memset(packetOut, 0, 512);
\r
589 memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover));
\r
590 memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
\r
591 memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6);
\r
592 memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions));
\r
593 memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6);
\r
594 IPSendPacket(NULL, frame, 400);
\r
595 request = DHCP_DISCOVER;
\r
596 DhcpRetrySeconds = 2;
\r
598 else if(state == 2 && memcmp(packet+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6) == 0)
\r
600 if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_OFFER && request == DHCP_DISCOVER)
\r
602 //Process DHCP Offer and send DHCP Request
\r
603 frame = IPFrameGet(0);
\r
606 packetOut = frame->packet;
\r
607 memset(packetOut, 0, 512);
\r
608 memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover));
\r
609 memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
\r
610 memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6);
\r
611 memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions));
\r
612 memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6);
\r
613 request = DHCP_REQUEST;
\r
614 packetOut[DHCP_MAGIC_COOKIE+6] = DHCP_REQUEST;
\r
615 ptr = packetOut+DHCP_MAGIC_COOKIE+sizeof(dhcpOptions)-1;
\r
616 ptr[0] = DHCP_REQUEST_IP;
\r
618 memcpy(ptr+2, packet+DHCP_YOUR_IP, 4);
\r
619 ptr[6] = DHCP_REQUEST_SERV_IP;
\r
621 memcpy(ptr+8, packet+DHCP_SERVER_IP, 4);
\r
622 ptr[12] = DHCP_END_OPTION;
\r
623 IPSendPacket(NULL, frame, 400);
\r
625 else if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_ACK && request == DHCP_REQUEST)
\r
629 DhcpRetrySeconds = 3600*4;
\r
630 memcpy(ipAddressPlasma, packet+DHCP_YOUR_IP, 4);
\r
631 printf("IP=%d.%d.%d.%d ", ipAddressPlasma[0], ipAddressPlasma[1],
\r
632 ipAddressPlasma[2], ipAddressPlasma[3]);
\r
633 memcpy(ipAddressGateway, packet+DHCP_GATEWAY_IP, 4);
\r
634 if(ipAddressGateway[0] == 0 && ipAddressGateway[1] == 0 &&
\r
635 ipAddressGateway[2] == 0 && ipAddressGateway[3] == 0)
\r
636 memcpy(ipAddressGateway, packet+DHCP_SERVER_IP, 4);
\r
637 printf("GW=%d.%d.%d.%d ", ipAddressGateway[0], ipAddressGateway[1],
\r
638 ipAddressGateway[2], ipAddressGateway[3]);
\r
639 memcpy(ethernetAddressGateway, packet+ETHERNET_SOURCE, 6);
\r
640 ptr2 = packet+DHCP_MAGIC_COOKIE+4;
\r
641 while(ptr2[0] != DHCP_END_OPTION && (int)(ptr2 - packet) < length)
\r
643 if(ptr2[0] == DHCP_PARAM_DNS)
\r
645 ipAddressDns = (ptr2[2] << 24) | (ptr2[3] << 16) | (ptr2[4] << 8) | ptr2[5];
\r
646 printf("DNS=%d.%d.%d.%d ", ptr2[2], ptr2[3], ptr2[4], ptr2[5]);
\r
648 ptr2 += ptr2[1] + 2;
\r
651 //Check if DHCP reply came from gateway
\r
652 if(memcmp(packet+IP_SOURCE, ipAddressGateway, 4))
\r
654 memset(ethernetAddressGateway, 0xff, 6);
\r
655 IPArp(ipAddressGateway); //Send ARP to gateway
\r
662 uint32 IPAddressSelf(void)
\r
664 return (ipAddressPlasma[0] << 24) | (ipAddressPlasma[1] << 16) |
\r
665 (ipAddressPlasma[2] << 8) | ipAddressPlasma[3];
\r
669 static int IPProcessTCPPacket(IPFrame *frameIn)
\r
672 int length, ip_length, bytes, rc=0, notify=0;
\r
673 IPSocket *socket, *socketNew;
\r
674 IPFrame *frameOut, *frame2, *framePrev;
\r
675 uint8 *packet, *packetOut;
\r
677 packet = frameIn->packet;
\r
678 length = frameIn->length;
\r
680 ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1];
\r
681 seq = (packet[TCP_SEQ] << 24) | (packet[TCP_SEQ+1] << 16) |
\r
682 (packet[TCP_SEQ+2] << 8) | packet[TCP_SEQ+3];
\r
683 ack = (packet[TCP_ACK] << 24) | (packet[TCP_ACK+1] << 16) |
\r
684 (packet[TCP_ACK+2] << 8) | packet[TCP_ACK+3];
\r
686 //Check if start of connection
\r
687 if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == TCP_FLAGS_SYN)
\r
691 //Check if duplicate SYN
\r
692 for(socket = SocketHead; socket; socket = socket->next)
\r
694 if(socket->state != IP_LISTEN &&
\r
695 packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
\r
696 memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 &&
\r
697 memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0)
\r
705 //Find an open port
\r
706 for(socket = SocketHead; socket; socket = socket->next)
\r
708 if(socket->state == IP_LISTEN &&
\r
709 packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
\r
710 memcmp(packet+TCP_DEST_PORT, socket->headerRcv+TCP_DEST_PORT, 2) == 0)
\r
712 //Create a new socket
\r
713 frameOut = IPFrameGet(FRAME_COUNT_SYNC);
\r
714 if(frameOut == NULL)
\r
716 socketNew = (IPSocket*)malloc(sizeof(IPSocket));
\r
717 if(socketNew == NULL)
\r
719 memcpy(socketNew, socket, sizeof(IPSocket));
\r
720 socketNew->state = IP_TCP;
\r
721 socketNew->timeout = SOCKET_TIMEOUT;
\r
722 socketNew->ack = seq;
\r
723 socketNew->ackProcessed = seq + 1;
\r
724 socketNew->seq = socketNew->ack + 0x12345678;
\r
725 socketNew->seqReceived = socketNew->seq;
\r
726 socketNew->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1];
\r
729 packetOut = frameOut->packet;
\r
730 EthernetCreateResponse(packetOut, packet, length);
\r
731 memcpy(socketNew->headerRcv, packet, TCP_SEQ);
\r
732 memcpy(socketNew->headerSend, packetOut, TCP_SEQ);
\r
733 packetOut[TCP_FLAGS] = TCP_FLAGS_SYN | TCP_FLAGS_ACK;
\r
735 packetOut[TCP_DATA] = 2; //maximum segment size = 536
\r
736 packetOut[TCP_DATA+1] = 4;
\r
737 packetOut[TCP_DATA+2] = 2;
\r
738 packetOut[TCP_DATA+3] = 24;
\r
739 TCPSendPacket(socketNew, frameOut, TCP_DATA+4);
\r
742 //Add socket to linked list
\r
743 OS_MutexPend(IPMutex);
\r
744 socketNew->next = SocketHead;
\r
745 socketNew->prev = NULL;
\r
747 SocketHead->prev = socketNew;
\r
748 SocketHead = socketNew;
\r
749 OS_MutexPost(IPMutex);
\r
750 if(socketNew->funcPtr)
\r
751 OS_Job(socketNew->funcPtr, socketNew, 0, 0);
\r
757 frameOut = IPFrameGet(0);
\r
758 if(frameOut == NULL)
\r
760 packetOut = frameOut->packet;
\r
761 EthernetCreateResponse(packetOut, packet, TCP_DATA);
\r
762 memset(packetOut+TCP_SEQ, 0, 4);
\r
764 packetOut[TCP_ACK] = (uint8)(seq >> 24);
\r
765 packetOut[TCP_ACK+1] = (uint8)(seq >> 16);
\r
766 packetOut[TCP_ACK+2] = (uint8)(seq >> 8);
\r
767 packetOut[TCP_ACK+3] = (uint8)seq;
\r
768 packetOut[TCP_HEADER_LENGTH] = 0x50;
\r
769 packetOut[TCP_FLAGS] = TCP_FLAGS_RST;
\r
770 IPSendPacket(NULL, frameOut, TCP_DATA);
\r
774 //Find an open socket
\r
775 for(socket = SocketHead; socket; socket = socket->next)
\r
777 if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
\r
778 memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 &&
\r
779 memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0)
\r
790 socket->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1];
\r
791 bytes = ip_length - (TCP_DATA - IP_VERSION_LENGTH);
\r
793 //Check if packets can be removed from retransmition list
\r
794 if(packet[TCP_FLAGS] & TCP_FLAGS_ACK)
\r
796 if(ack != socket->seqReceived)
\r
798 OS_MutexPend(IPMutex);
\r
799 for(frame2 = FrameResendHead; frame2; )
\r
801 framePrev = frame2;
\r
802 frame2 = frame2->next;
\r
803 if(framePrev->socket == socket && (int)(ack - framePrev->seqEnd) >= 0)
\r
805 //Remove packet from retransmition queue
\r
806 if(socket->timeout)
\r
807 socket->timeout = socket->timeoutReset;
\r
808 FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
\r
809 FrameFree(framePrev);
\r
812 OS_MutexPost(IPMutex);
\r
813 socket->seqReceived = ack;
\r
814 socket->resentDone = 0;
\r
816 else if(ack == socket->seqReceived && bytes == 0 &&
\r
817 (packet[TCP_FLAGS] & (TCP_FLAGS_RST | TCP_FLAGS_FIN)) == 0 &&
\r
818 socket->resentDone == 0)
\r
820 //Detected that packet was lost, resend all
\r
823 OS_MutexPend(IPMutex);
\r
824 for(frame2 = FrameResendHead; frame2; )
\r
826 framePrev = frame2;
\r
827 frame2 = frame2->next;
\r
828 if(framePrev->socket == socket)
\r
830 //Remove packet from retransmition queue
\r
831 FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
\r
832 IPSendFrame(framePrev);
\r
835 OS_MutexPost(IPMutex);
\r
836 socket->resentDone = 1;
\r
841 if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) ==
\r
842 (TCP_FLAGS_SYN | TCP_FLAGS_ACK))
\r
845 socket->ack = seq + 1;
\r
846 socket->ackProcessed = seq + 1;
\r
847 frameOut = IPFrameGet(FRAME_COUNT_SEND);
\r
850 frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
\r
851 TCPSendPacket(socket, frameOut, TCP_DATA);
\r
853 if(socket->funcPtr)
\r
854 OS_Job(socket->funcPtr, socket, 0, 0);
\r
857 if(packet[TCP_HEADER_LENGTH] != 0x50)
\r
860 printf("length error\n");
\r
864 //Check if RST flag set
\r
865 if(packet[TCP_FLAGS] & TCP_FLAGS_RST)
\r
870 //Copy packet into socket
\r
871 else if(socket->ack == seq && bytes > 0)
\r
873 //Insert packet into socket linked list
\r
875 if(socket->timeout)
\r
876 socket->timeout = socket->timeoutReset;
\r
879 if(frameIn->length > ip_length + IP_VERSION_LENGTH)
\r
880 frameIn->length = (uint16)(ip_length + IP_VERSION_LENGTH);
\r
881 FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn);
\r
882 socket->ack += bytes;
\r
885 frameOut = IPFrameGet(FRAME_COUNT_SEND);
\r
888 frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
\r
889 TCPSendPacket(socket, frameOut, TCP_DATA);
\r
897 //Ack with current offset since data missing
\r
898 frameOut = IPFrameGet(FRAME_COUNT_SEND);
\r
901 frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
\r
902 TCPSendPacket(socket, frameOut, TCP_DATA);
\r
906 //Check if FIN flag set
\r
907 if(packet[TCP_FLAGS] & TCP_FLAGS_FIN && socket->ack >= seq)
\r
910 socket->timeout = SOCKET_TIMEOUT;
\r
913 frameOut = IPFrameGet(0);
\r
914 if(frameOut == NULL)
\r
916 packetOut = frameOut->packet;
\r
917 packetOut[TCP_FLAGS] = TCP_FLAGS_ACK;
\r
919 TCPSendPacket(socket, frameOut, TCP_DATA);
\r
920 if(socket->state == IP_FIN_SERVER)
\r
921 socket->timeout = SOCKET_TIMEOUT;
\r
922 else if(socket->state == IP_TCP)
\r
923 socket->state = IP_FIN_CLIENT;
\r
926 //Notify application
\r
927 if(socket->funcPtr && notify)
\r
928 OS_Job(socket->funcPtr, socket, 0, 0);
\r
933 int IPProcessEthernetPacket(IPFrame *frameIn, int length)
\r
938 uint8 *packet, *packetOut;
\r
940 packet = frameIn->packet;
\r
941 frameIn->length = (uint16)length;
\r
943 if(packet[ETHERNET_FRAME_TYPE] != 0x08 || frameIn->length > PACKET_SIZE)
\r
944 return 0; //wrong ethernet type, packet not used
\r
947 if(packet[ETHERNET_FRAME_TYPE+1] == 0x06)
\r
949 //Check if ARP reply
\r
950 if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) == 0 &&
\r
951 packet[ARP_OP+1] == 2)
\r
953 memcpy(ArpCache[ArpCacheIndex].ip, packet+ARP_IP_SENDER, 4);
\r
954 memcpy(ArpCache[ArpCacheIndex].mac, packet+ARP_ETHERNET_SENDER, 6);
\r
955 if(++ArpCacheIndex >= sizeof(ArpCache) / sizeof(ArpCache_t))
\r
957 if(memcmp(packet+ARP_IP_SENDER, ipAddressGateway, 4) == 0)
\r
959 //Found MAC address for gateway
\r
960 memcpy(ethernetAddressGateway, packet+ARP_ETHERNET_SENDER, 6);
\r
965 //Check if ARP request
\r
966 if(packet[ARP_OP] != 0 || packet[ARP_OP+1] != 1 ||
\r
967 memcmp(packet+ARP_IP_TARGET, ipAddressPlasma, 4))
\r
969 //Create ARP response
\r
970 frameOut = IPFrameGet(0);
\r
971 if(frameOut == NULL)
\r
973 packetOut = frameOut->packet;
\r
974 memcpy(packetOut, packet, frameIn->length);
\r
975 memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6);
\r
976 memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
\r
977 packetOut[ARP_OP+1] = 2; //ARP reply
\r
978 memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6);
\r
979 memcpy(packetOut+ARP_IP_SENDER, packet+ARP_IP_TARGET, 4);
\r
980 memcpy(packetOut+ARP_ETHERNET_TARGET, packet+ARP_ETHERNET_SENDER, 6);
\r
981 memcpy(packetOut+ARP_IP_TARGET, packet+ARP_IP_SENDER, 4);
\r
982 IPSendPacket(NULL, frameOut, frameIn->length);
\r
986 //Check if proper type of packet
\r
987 ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1];
\r
988 if(frameIn->length < UDP_DATA || ip_length > frameIn->length - IP_VERSION_LENGTH)
\r
990 if(packet[ETHERNET_FRAME_TYPE+1] != 0x00 ||
\r
991 packet[IP_VERSION_LENGTH] != 0x45)
\r
994 //Check if DHCP reply
\r
995 if(packet[IP_PROTOCOL] == 0x11 &&
\r
996 packet[UDP_SOURCE_PORT] == 0 && packet[UDP_SOURCE_PORT+1] == 67 &&
\r
997 packet[UDP_DEST_PORT] == 0 && packet[UDP_DEST_PORT+1] == 68)
\r
999 IPDhcp(packet, frameIn->length, 2); //DHCP reply
\r
1003 //Check if correct destination address
\r
1004 if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) ||
\r
1005 memcmp(packet+IP_DEST, ipAddressPlasma, 4))
\r
1007 rc = EthernetVerifyChecksums(packet, frameIn->length);
\r
1009 if(rc && FrameSendFunc)
\r
1017 if(packet[IP_PROTOCOL] == 1)
\r
1019 if(packet[PING_TYPE] == 0) //PING reply
\r
1021 for(socket = SocketHead; socket; socket = socket->next)
\r
1023 if(socket->state == IP_PING &&
\r
1024 memcmp(packet+IP_SOURCE, socket->headerSend+IP_DEST, 4) == 0)
\r
1026 OS_Job(socket->funcPtr, socket, 0, 0);
\r
1031 if(packet[PING_TYPE] != 8)
\r
1033 frameOut = IPFrameGet(FRAME_COUNT_SEND);
\r
1034 if(frameOut == NULL)
\r
1036 packetOut = frameOut->packet;
\r
1037 EthernetCreateResponse(packetOut, packet, frameIn->length);
\r
1038 frameOut->packet[PING_TYPE] = 0; //PING reply
\r
1039 IPSendPacket(NULL, frameOut, frameIn->length);
\r
1044 if(packet[IP_PROTOCOL] == 0x06)
\r
1046 return IPProcessTCPPacket(frameIn);
\r
1050 if(packet[IP_PROTOCOL] == 0x11)
\r
1052 //Find open socket
\r
1053 for(socket = SocketHead; socket; socket = socket->next)
\r
1055 if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
\r
1056 memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 &&
\r
1057 memcmp(packet+UDP_SOURCE_PORT, socket->headerRcv+UDP_SOURCE_PORT, 2) == 0)
\r
1063 if(socket == NULL)
\r
1065 //Find listening socket
\r
1066 for(socket = SocketHead; socket; socket = socket->next)
\r
1068 if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] &&
\r
1069 memcmp(packet+UDP_DEST_PORT, socket->headerRcv+UDP_DEST_PORT, 2) == 0)
\r
1071 EthernetCreateResponse(socket->headerSend, packet, UDP_DATA);
\r
1081 FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn);
\r
1082 OS_Job(socket->funcPtr, socket, 0, 0);
\r
1091 static void IPMainThread(void *arg)
\r
1093 uint32 message[4];
\r
1095 IPFrame *frame, *frameOut=NULL;
\r
1096 uint32 ticks, ticksLast;
\r
1099 ticksLast = OS_ThreadTime();
\r
1100 memset(message, 0, sizeof(message));
\r
1105 rc = OS_MQueueGet(IPMQueue, message, 10);
\r
1108 frame = (IPFrame*)message[1];
\r
1109 if(message[0] == 0) //frame received
\r
1112 frame->length = (uint16)message[2];
\r
1113 rc = IPProcessEthernetPacket(frame, frame->length);
\r
1117 else if(message[0] == 1) //frame sent
\r
1120 assert(frame == frameOut);
\r
1121 IPFrameReschedule(frame);
\r
1124 else if(message[0] == 2) //frame ready to send
\r
1129 if(frameOut == NULL)
\r
1131 OS_MutexPend(IPMutex);
\r
1132 frameOut = FrameSendTail;
\r
1134 FrameRemove(&FrameSendHead, &FrameSendTail, frameOut);
\r
1135 OS_MutexPost(IPMutex);
\r
1139 UartPacketSend(frameOut->packet, frameOut->length);
\r
1143 ticks = OS_ThreadTime();
\r
1144 if(ticks - ticksLast > 100)
\r
1147 ticksLast = ticks;
\r
1154 uint8 *MyPacketGet(void)
\r
1156 return (uint8*)IPFrameGet(FRAME_COUNT_RCV);
\r
1160 //Set FrameSendFunction only if single threaded
\r
1161 void IPInit(IPFuncPtr frameSendFunction, uint8 macAddress[6], char name[6])
\r
1167 memcpy(ethernetAddressPlasma, macAddress, 6);
\r
1169 memcpy(dhcpOptions+18, name, 6);
\r
1170 FrameSendFunc = frameSendFunction;
\r
1171 IPMutex = OS_MutexCreate("IPSem");
\r
1172 IPMQueue = OS_MQueueCreate("IPMQ", FRAME_COUNT*2, 32);
\r
1173 for(i = 0; i < FRAME_COUNT; ++i)
\r
1175 frame = (IPFrame*)malloc(sizeof(IPFrame));
\r
1176 memset(frame, 0, sizeof(IPFrame));
\r
1177 frame->next = FrameFreeHead;
\r
1178 frame->prev = NULL;
\r
1179 FrameFreeHead = frame;
\r
1181 FrameFreeCount = FRAME_COUNT;
\r
1183 UartPacketConfig(MyPacketGet, PACKET_SIZE, IPMQueue);
\r
1184 if(frameSendFunction == NULL)
\r
1185 IPThread = OS_ThreadCreate("TCP/IP", IPMainThread, NULL, 240, 6000);
\r
1187 IPDhcp(NULL, 360, 1); //Send DHCP request
\r
1191 //To open a socket for listen set ipAddress to 0
\r
1192 IPSocket *IPOpen(IPMode_e mode, uint32 ipAddress, uint32 port, IPFuncPtr funcPtr)
\r
1195 uint8 *ptrSend, *ptrRcv;
\r
1197 static int portSource=0x1007;
\r
1199 socket = (IPSocket*)malloc(sizeof(IPSocket));
\r
1200 if(socket == NULL)
\r
1202 memset(socket, 0, sizeof(IPSocket));
\r
1203 socket->prev = NULL;
\r
1204 socket->state = IP_LISTEN;
\r
1205 socket->timeout = 0;
\r
1206 socket->timeoutReset = SOCKET_TIMEOUT;
\r
1207 socket->frameReadHead = NULL;
\r
1208 socket->frameReadTail = NULL;
\r
1209 socket->readOffset = 0;
\r
1210 socket->funcPtr = funcPtr;
\r
1211 socket->userData = 0;
\r
1212 socket->userFunc = NULL;
\r
1213 socket->userPtr = NULL;
\r
1214 socket->seqWindow = 2048;
\r
1215 ptrSend = socket->headerSend;
\r
1216 ptrRcv = socket->headerRcv;
\r
1218 if(ipAddress == 0)
\r
1220 //Setup listing port
\r
1221 socket->headerRcv[TCP_DEST_PORT] = (uint8)(port >> 8);
\r
1222 socket->headerRcv[TCP_DEST_PORT+1] = (uint8)port;
\r
1226 //Setup sending packet
\r
1227 memset(ptrSend, 0, UDP_LENGTH);
\r
1228 memset(ptrRcv, 0, UDP_LENGTH);
\r
1231 if(ipAddress != IPAddressSelf())
\r
1232 memcpy(ptrSend+ETHERNET_DEST, ethernetAddressGateway, 6);
\r
1234 memcpy(ptrSend+ETHERNET_DEST, ethernetAddressPlasma, 6);
\r
1235 memcpy(ptrSend+ETHERNET_SOURCE, ethernetAddressPlasma, 6);
\r
1236 ptrSend[ETHERNET_FRAME_TYPE] = 0x08;
\r
1239 ptrSend[IP_VERSION_LENGTH] = 0x45;
\r
1240 ptrSend[IP_TIME_TO_LIVE] = 0x80;
\r
1242 //Setup IP addresses
\r
1243 memcpy(ptrSend+IP_SOURCE, ipAddressPlasma, 4);
\r
1244 ptrSend[IP_DEST] = (uint8)(ipAddress >> 24);
\r
1245 ptrSend[IP_DEST+1] = (uint8)(ipAddress >> 16);
\r
1246 ptrSend[IP_DEST+2] = (uint8)(ipAddress >> 8);
\r
1247 ptrSend[IP_DEST+3] = (uint8)ipAddress;
\r
1248 ptrRcv[IP_SOURCE] = (uint8)(ipAddress >> 24);
\r
1249 ptrRcv[IP_SOURCE+1] = (uint8)(ipAddress >> 16);
\r
1250 ptrRcv[IP_SOURCE+2] = (uint8)(ipAddress >> 8);
\r
1251 ptrRcv[IP_SOURCE+3] = (uint8)ipAddress;
\r
1252 memcpy(ptrRcv+IP_DEST, ipAddressPlasma, 4);
\r
1255 ptrSend[TCP_SOURCE_PORT] = (uint8)(portSource >> 8);
\r
1256 ptrSend[TCP_SOURCE_PORT+1] = (uint8)portSource;
\r
1257 ptrSend[TCP_DEST_PORT] = (uint8)(port >> 8);
\r
1258 ptrSend[TCP_DEST_PORT+1] = (uint8)port;
\r
1259 ptrRcv[TCP_SOURCE_PORT] = (uint8)(port >> 8);
\r
1260 ptrRcv[TCP_SOURCE_PORT+1] = (uint8)port;
\r
1261 ptrRcv[TCP_DEST_PORT] = (uint8)(portSource >> 8);
\r
1262 ptrRcv[TCP_DEST_PORT+1] = (uint8)portSource;
\r
1266 if(mode == IP_MODE_TCP)
\r
1269 socket->state = IP_TCP;
\r
1271 socket->state = IP_LISTEN;
\r
1272 ptrSend[IP_PROTOCOL] = 0x06; //TCP
\r
1273 ptrRcv[IP_PROTOCOL] = 0x06;
\r
1275 else if(mode == IP_MODE_UDP)
\r
1277 socket->state = IP_UDP;
\r
1278 ptrSend[IP_PROTOCOL] = 0x11; //UDP
\r
1279 ptrRcv[IP_PROTOCOL] = 0x11;
\r
1281 else if(mode == IP_MODE_PING)
\r
1283 socket->state = IP_PING;
\r
1284 ptrSend[IP_PROTOCOL] = 0x01; //PING
\r
1285 memset(ptrSend+PING_TYPE, 0, 8);
\r
1286 ptrSend[PING_TYPE] = 8; //SEND
\r
1289 //Add socket to linked list
\r
1290 OS_MutexPend(IPMutex);
\r
1291 socket->next = SocketHead;
\r
1292 socket->prev = NULL;
\r
1294 SocketHead->prev = socket;
\r
1295 SocketHead = socket;
\r
1296 OS_MutexPost(IPMutex);
\r
1298 if(mode == IP_MODE_TCP && ipAddress)
\r
1301 socket->seq = 0x01234567;
\r
1302 frame = IPFrameGet(0);
\r
1305 frame->packet[TCP_FLAGS] = TCP_FLAGS_SYN;
\r
1306 frame->packet[TCP_DATA] = 2; //maximum segment size = 536
\r
1307 frame->packet[TCP_DATA+1] = 4;
\r
1308 frame->packet[TCP_DATA+2] = 2;
\r
1309 frame->packet[TCP_DATA+3] = 24;
\r
1310 TCPSendPacket(socket, frame, TCP_DATA+4);
\r
1318 void IPWriteFlush(IPSocket *socket)
\r
1321 if(socket->frameSend && socket->state != IP_UDP &&
\r
1322 socket->state != IP_PING)
\r
1324 packetOut = socket->frameSend->packet;
\r
1325 packetOut[TCP_FLAGS] = TCP_FLAGS_ACK | TCP_FLAGS_PSH;
\r
1326 TCPSendPacket(socket, socket->frameSend, TCP_DATA + socket->sendOffset);
\r
1327 socket->seq += socket->sendOffset;
\r
1328 socket->frameSend = NULL;
\r
1329 socket->sendOffset = 0;
\r
1334 uint32 IPWrite(IPSocket *socket, const uint8 *buf, uint32 length)
\r
1336 IPFrame *frameOut;
\r
1338 uint32 bytes, count=0, tries=0;
\r
1340 OS_Thread_t *self;
\r
1342 if(socket->state > IP_TCP)
\r
1345 if(socket->timeout)
\r
1346 socket->timeout = socket->timeoutReset;
\r
1348 #ifdef INCLUDE_FILESYS
\r
1349 if(socket->fileOut) //override stdout
\r
1350 return fwrite((char*)buf, 1, length, socket->fileOut);
\r
1353 //printf("IPWrite(0x%x, %d)", Socket, Length);
\r
1354 self = OS_ThreadSelf();
\r
1357 //Rate limit output
\r
1358 if(socket->seq - socket->seqReceived >= SEND_WINDOW)
\r
1360 //printf("l(%d,%d,%d) ", socket->seq - socket->seqReceived, socket->seq, socket->seqReceived);
\r
1361 if(self != IPThread && ++tries < 200)
\r
1363 OS_ThreadSleep(1);
\r
1368 while(socket->frameSend == NULL)
\r
1370 socket->frameSend = IPFrameGet(FRAME_COUNT_SEND);
\r
1371 socket->sendOffset = 0;
\r
1372 if(socket->frameSend == NULL)
\r
1375 if(self == IPThread || ++tries > 200)
\r
1378 OS_ThreadSleep(1);
\r
1381 frameOut = socket->frameSend;
\r
1382 offset = socket->sendOffset;
\r
1383 if(frameOut == NULL)
\r
1385 packetOut = frameOut->packet;
\r
1387 if(socket->state == IP_PING)
\r
1390 memcpy(packetOut, socket->headerSend, PING_DATA);
\r
1391 memcpy(packetOut+PING_DATA, buf, bytes);
\r
1392 IPSendPacket(socket, socket->frameSend, PING_DATA + bytes);
\r
1393 socket->frameSend = NULL;
\r
1395 else if(socket->state != IP_UDP)
\r
1397 bytes = 512 - offset;
\r
1398 if(bytes > length)
\r
1400 socket->sendOffset += bytes;
\r
1401 memcpy(packetOut+TCP_DATA+offset, buf, bytes);
\r
1402 if(socket->sendOffset >= 512)
\r
1403 IPWriteFlush(socket);
\r
1404 //if(Socket->seq - Socket->seqReceived > Socket->seqWindow)
\r
1407 // OS_ThreadSleep(10);
\r
1413 memcpy(packetOut+UDP_DATA+offset, buf, bytes);
\r
1414 memcpy(packetOut, socket->headerSend, UDP_LENGTH);
\r
1415 IPSendPacket(socket, socket->frameSend, UDP_DATA + bytes);
\r
1416 socket->frameSend = NULL;
\r
1426 uint32 IPRead(IPSocket *socket, uint8 *buf, uint32 length)
\r
1428 IPFrame *frame, *frame2;
\r
1429 int count=0, bytes, offset;
\r
1431 #ifdef INCLUDE_FILESYS
\r
1432 if(socket->fileIn) //override stdin
\r
1434 bytes = fread(buf, 1, 1, socket->fileIn);
\r
1438 fclose(socket->fileIn);
\r
1439 socket->fileIn = NULL;
\r
1446 if(socket->state == IP_UDP)
\r
1447 offset = UDP_DATA;
\r
1449 offset = TCP_DATA;
\r
1451 OS_MutexPend(IPMutex);
\r
1452 for(frame = socket->frameReadTail; length && frame; )
\r
1454 bytes = frame->length - offset - socket->readOffset;
\r
1455 if(bytes > (int)length)
\r
1457 memcpy(buf, frame->packet + offset + socket->readOffset, bytes);
\r
1459 socket->readOffset += bytes;
\r
1463 //Check if done with packet
\r
1465 frame = frame->prev;
\r
1466 if(socket->readOffset == frame2->length - offset)
\r
1468 //Remove packet from socket linked list
\r
1469 socket->readOffset = 0;
\r
1470 FrameRemove(&socket->frameReadHead, &socket->frameReadTail, frame2);
\r
1471 socket->ackProcessed += frame2->length - offset;
\r
1472 if(socket->state == IP_TCP &&
\r
1473 socket->ack - socket->ackProcessed > RECEIVE_WINDOW - 2048)
\r
1475 //Update receive window for flow control
\r
1476 frame2->packet[TCP_FLAGS] = TCP_FLAGS_ACK;
\r
1477 TCPSendPacket(socket, frame2, TCP_DATA);
\r
1480 FrameFree(frame2);
\r
1483 OS_MutexPost(IPMutex);
\r
1488 static void IPClose2(IPSocket *socket)
\r
1490 IPFrame *frame, *framePrev;
\r
1492 //printf("IPClose2(%x) ", (int)socket);
\r
1494 OS_MutexPend(IPMutex);
\r
1496 //Remove pending packets
\r
1497 for(frame = FrameSendHead; frame; )
\r
1499 framePrev = frame;
\r
1500 frame = frame->next;
\r
1501 if(framePrev->socket == socket)
\r
1503 FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
\r
1504 FrameFree(framePrev);
\r
1508 //Remove packets from retransmision list
\r
1509 for(frame = FrameResendHead; frame; )
\r
1511 framePrev = frame;
\r
1512 frame = frame->next;
\r
1513 if(framePrev->socket == socket)
\r
1515 FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);
\r
1516 FrameFree(framePrev);
\r
1520 //Remove packets from socket read linked list
\r
1521 for(frame = socket->frameReadHead; frame; )
\r
1523 framePrev = frame;
\r
1524 frame = frame->next;
\r
1525 FrameRemove(&socket->frameReadHead, &socket->frameReadTail, framePrev);
\r
1526 FrameFree(framePrev);
\r
1529 //Give application time to stop using socket
\r
1530 socket->timeout = SOCKET_TIMEOUT;
\r
1531 socket->state = IP_CLOSED;
\r
1533 OS_MutexPost(IPMutex);
\r
1537 void IPClose(IPSocket *socket)
\r
1539 IPFrame *frameOut;
\r
1541 //printf("IPClose(%x) ", (int)socket);
\r
1543 IPWriteFlush(socket);
\r
1544 if(socket->state <= IP_UDP)
\r
1549 frameOut = IPFrameGet(0);
\r
1550 if(frameOut == NULL)
\r
1552 frameOut->packet[TCP_FLAGS] = TCP_FLAGS_FIN | TCP_FLAGS_ACK;
\r
1553 TCPSendPacket(socket, frameOut, TCP_DATA);
\r
1555 socket->timeout = SOCKET_TIMEOUT;
\r
1556 socket->timeoutReset = SOCKET_TIMEOUT;
\r
1557 socket->state = IP_FIN_SERVER;
\r
1561 void IPPrintf(IPSocket *socket, char *message,
\r
1562 int arg0, int arg1, int arg2, int arg3)
\r
1565 if(socket == NULL)
\r
1567 printf(message, arg0, arg1, arg2, arg3);
\r
1570 if(strcmp(message, "%s") == 0)
\r
1571 IPWrite(socket, (uint8*)arg0, (int)strlen((char*)arg0));
\r
1574 sprintf(buf, message, arg0, arg1, arg2, arg3, 0, 0, 0, 0);
\r
1575 IPWrite(socket, (uint8*)buf, (int)strlen(buf));
\r
1577 if(socket->dontFlush == 0 || strstr(message, "\n"))
\r
1578 IPWriteFlush(socket);
\r
1584 IPFrame *frame, *frame2;
\r
1585 IPSocket *socket, *socket2;
\r
1586 unsigned long ticks;
\r
1587 static unsigned long ticksPrev=0, ticksPrev2=0;
\r
1589 ticks = OS_ThreadTime();
\r
1591 ticks = ticksPrev + 100;
\r
1593 if(ticks - ticksPrev >= 95)
\r
1595 if(IPVerbose && (Seconds % 60) == 0)
\r
1597 if(FrameFreeCount >= FRAME_COUNT-1)
\r
1600 printf("T(%d)", FrameFreeCount);
\r
1603 if(--DhcpRetrySeconds <= 0)
\r
1604 IPDhcp(NULL, 400, 1); //DHCP request
\r
1607 OS_MutexPend(IPMutex);
\r
1609 //Retransmit timeout packets
\r
1610 for(frame = FrameResendHead; frame; )
\r
1613 frame = frame->next;
\r
1614 frame2->timeout = (short)(frame2->timeout - (ticks - ticksPrev2));
\r
1615 if(--frame2->timeout <= 0)
\r
1618 printf("r" /*"(%x,%x,%d,%d,%d)"*/, (int)frame2, (int)frame2->socket,
\r
1619 frame2->retryCnt, frame2->length - TCP_DATA,
\r
1620 frame2->socket->state);
\r
1621 FrameRemove(&FrameResendHead, &FrameResendTail, frame2);
\r
1622 if(frame2->retryCnt < 4 && frame2->socket->state < IP_CLOSED)
\r
1623 IPSendFrame(frame2);
\r
1626 if(frame2->socket->state == IP_TCP)
\r
1627 IPClose(frame2->socket);
\r
1628 FrameFree(frame2);
\r
1633 if(ticks - ticksPrev >= 95)
\r
1635 //Close timed out sockets
\r
1636 for(socket = SocketHead; socket; )
\r
1639 socket = socket->next;
\r
1640 if(socket2->timeout && --socket2->timeout == 0)
\r
1642 socket2->timeout = SOCKET_TIMEOUT;
\r
1643 if(socket2->state <= IP_TCP || socket2->state == IP_FIN_CLIENT)
\r
1645 else if(socket2->state != IP_CLOSED)
\r
1646 IPClose2(socket2);
\r
1649 if(socket2->prev == NULL)
\r
1650 SocketHead = socket2->next;
\r
1652 socket2->prev->next = socket2->next;
\r
1654 socket2->next->prev = socket2->prev;
\r
1655 //printf("freeSocket(%x) ", (int)socket2);
\r
1660 ticksPrev = ticks;
\r
1662 OS_MutexPost(IPMutex);
\r
1663 ticksPrev2 = ticks;
\r
1667 static void DnsCallback(IPSocket *socket)
\r
1669 uint8 buf[200], *ptr;
\r
1673 memset(buf, 0, sizeof(buf));
\r
1674 bytes = IPRead(socket, buf, sizeof(buf));
\r
1675 if(buf[DNS_NUM_ANSWERS_RR+1])
\r
1677 for(ptr = buf + DNS_QUESTIONS; ptr + 14 <= buf + bytes; ++ptr)
\r
1679 if(ptr[0] == 0 && ptr[1] == 1 && ptr[2] == 0 && ptr[3] == 1 &&
\r
1680 ptr[8] == 0 && ptr[9] == 4)
\r
1682 ipAddress = (ptr[10] << 24) | (ptr[11] << 16) | (ptr[12] << 8) | ptr[13];
\r
1683 printf("ipAddress = %d.%d.%d.%d\n", ptr[10], ptr[11], ptr[12], ptr[13]);
\r
1684 socket->userData = ipAddress;
\r
1685 if(socket->userFunc)
\r
1687 socket->userFunc(socket, ipAddress, socket->userPtr);
\r
1697 void IPResolve(char *name, IPFuncPtr resolvedFunc, void *arg)
\r
1699 uint8 buf[200], *ptr;
\r
1703 socket = IPOpen(IP_MODE_UDP, ipAddressDns, DNS_PORT, DnsCallback);
\r
1704 memset(buf, 0, sizeof(buf));
\r
1705 buf[DNS_ID+1] = 1;
\r
1706 buf[DNS_FLAGS] = 1;
\r
1707 buf[DNS_NUM_QUESTIONS+1] = 1;
\r
1710 ptr = buf + DNS_QUESTIONS;
\r
1711 strncpy((char*)ptr+1, name, 100);
\r
1715 for(i = 0; i < 100; ++i)
\r
1717 if(ptr[i+1] == '.' || ptr[i+1] == 0)
\r
1719 ptr[0] = (uint8)i;
\r
1726 ptr[1] = DNS_QUERY_TYPE_IP;
\r
1727 ptr[3] = DNS_QUERY_CLASS;
\r
1728 length = (int)(ptr - buf) + 4;
\r
1732 socket->userFunc = (IPFuncPtr)resolvedFunc;
\r
1733 socket->userPtr = arg;
\r
1734 socket->userData = 0;
\r
1735 IPWrite(socket, buf, length);
\r