]> rtime.felk.cvut.cz Git - fpga/plasma.git/blob - kernel/tcpip.c
Local copy of Plasma MIPS project.
[fpga/plasma.git] / kernel / tcpip.c
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
5  * FILENAME: tcpip.c\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
9  * DESCRIPTION:\r
10  *    Plasma TCP/IP Protocol Stack\r
11  *\r
12  *    Possible call stack when receiving a packet:\r
13  *       IPMainThread()\r
14  *          IPProcessEthernetPacket()\r
15  *             IPProcessTCPPacket()\r
16  *                TCPSendPacket()\r
17  *                   IPSendPacket()\r
18  *                      IPChecksum()\r
19  *                      IPSendFrame()\r
20  *                         FrameInsert()\r
21  *--------------------------------------------------------------------*/\r
22 #ifdef WIN32\r
23 #include <stdio.h>\r
24 #include <stdlib.h>\r
25 #include <string.h>\r
26 #include <assert.h>\r
27 #define _LIBC\r
28 #endif\r
29 #include "rtos.h"\r
30 #define IPPRINTF\r
31 #include "tcpip.h"\r
32 \r
33 \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
38 \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
50 \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
62 \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
69 \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
75 #define UDP_DATA              42\r
76 \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
94 \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
99 #define DHCP_ACK              5\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
109 \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
118 \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
126 \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
138 \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
144 \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
152 \r
153 static void IPClose2(IPSocket *Socket);\r
154 static void IPArp(unsigned char ipAddress[4]);\r
155 \r
156 typedef struct ArpCache_s {\r
157    unsigned char ip[4];\r
158    unsigned char mac[6];\r
159 } ArpCache_t;\r
160 static ArpCache_t ArpCache[10];\r
161 static int ArpCacheIndex;\r
162 \r
163 static uint8 ethernetAddressGateway[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
164 #ifndef WIN32\r
165 static uint8 ethernetAddressPlasma[] =  {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4};\r
166 #else\r
167 static uint8 ethernetAddressPlasma[] =  {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd5};\r
168 #endif\r
169 \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
173 \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
187 int IPVerbose=1;\r
188 \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
192    0x08, 0x00, \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
198 };\r
199 \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
204 #ifndef WIN32\r
205    0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'a',             //Host name\r
206 #else\r
207    0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'b',             //Host name\r
208 #endif\r
209    0x37, 0x03, DHCP_PARAM_SUBNET, DHCP_PARAM_ROUTER, DHCP_PARAM_DNS, //Parameters\r
210    DHCP_END_OPTION\r
211 };\r
212 \r
213 \r
214 //Get a free frame; can be called from an ISR\r
215 IPFrame *IPFrameGet(int freeCount)\r
216 {\r
217    IPFrame *frame=NULL;\r
218    uint32 state;\r
219 \r
220    state = OS_CriticalBegin();\r
221    if(FrameFreeCount > freeCount)\r
222    {\r
223       frame = FrameFreeHead;\r
224       if(FrameFreeHead)\r
225       {\r
226          FrameFreeHead = FrameFreeHead->next;\r
227          --FrameFreeCount;\r
228       }\r
229    }\r
230    OS_CriticalEnd(state);\r
231    if(frame)\r
232    {\r
233       assert(frame->state == 0);\r
234       frame->state = 1;\r
235    }\r
236    return frame;\r
237 }\r
238 \r
239 \r
240 static void FrameFree(IPFrame *frame)\r
241 {\r
242    uint32 state;\r
243 \r
244    assert(frame->state == 1);\r
245    frame->state = 0;\r
246    state = OS_CriticalBegin();\r
247    frame->next = FrameFreeHead;\r
248    FrameFreeHead = frame;\r
249    ++FrameFreeCount;\r
250    OS_CriticalEnd(state);\r
251 }\r
252 \r
253 \r
254 static void FrameInsert(IPFrame **head, IPFrame **tail, IPFrame *frame)\r
255 {\r
256    assert(frame->state == 1);\r
257    frame->state = 2;\r
258    OS_MutexPend(IPMutex);\r
259    frame->prev = NULL;\r
260    frame->next = *head;\r
261    if(*head)\r
262       (*head)->prev = frame;\r
263    *head = frame;\r
264    if(*tail == NULL)\r
265       *tail = frame;\r
266    OS_MutexPost(IPMutex);\r
267 }\r
268 \r
269 \r
270 static void FrameRemove(IPFrame **head, IPFrame **tail, IPFrame *frame)\r
271 {\r
272    assert(frame->state == 2);\r
273    if(frame->state != 2)\r
274    {\r
275       printf("frame->state=%d\n", frame->state);\r
276       return;\r
277    }\r
278    frame->state = 1;\r
279    if(frame->prev)\r
280       frame->prev->next = frame->next;\r
281    else\r
282       *head = frame->next;\r
283    if(frame->next)\r
284       frame->next->prev = frame->prev;\r
285    else\r
286       *tail = frame->prev;\r
287    frame->prev = NULL;\r
288    frame->next = NULL;\r
289 }\r
290 \r
291 \r
292 static int IPChecksum(int checksum, const unsigned char *data, int length)\r
293 {\r
294    int i;\r
295    checksum = ~checksum & 0xffff;\r
296    for(i = 0; i < length-1; i += 2)\r
297    {\r
298       checksum += (data[i] << 8) | data[i+1];\r
299    }\r
300    if(i < length)\r
301       checksum += data[i] << 8;\r
302    while(checksum >> 16)\r
303       checksum = (checksum & 0xffff) + (checksum >> 16);\r
304    checksum = ~checksum & 0xffff;\r
305    return checksum;\r
306 }\r
307 \r
308 \r
309 static int EthernetVerifyChecksums(const unsigned char *packet, int length)\r
310 {\r
311    int checksum, length2;\r
312    unsigned char pseudo[12];\r
313 \r
314    //Calculate checksums\r
315    if(packet[ETHERNET_FRAME_TYPE+1] == 0x00)  //IP\r
316    {\r
317       checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20);\r
318       if(checksum)\r
319          return -1;\r
320       if(packet[IP_PROTOCOL] == 0x01)         //PING\r
321       {\r
322          checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE);\r
323       }\r
324       else if(packet[IP_PROTOCOL] == 0x11)    //UDP\r
325       {\r
326          if(packet[UDP_CHECKSUM] == 0 && packet[UDP_CHECKSUM+1] == 0)\r
327             return 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
336       }\r
337       else if(packet[IP_PROTOCOL] == 0x06)    //TCP\r
338       {\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
349       }\r
350       if(checksum)\r
351          return -1;\r
352    }\r
353    return 0;\r
354 }\r
355 \r
356 \r
357 static void IPFrameReschedule(IPFrame *frame)\r
358 {\r
359    int length;\r
360    length = frame->length - TCP_DATA;\r
361    if(frame->packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN))\r
362       ++length;\r
363    if(frame->socket == NULL || frame->socket->state == IP_UDP || length == 0 ||\r
364       frame->socket->state == IP_PING || ++frame->retryCnt > 4)\r
365    {\r
366       FrameFree(frame);     //can't be ACK'ed\r
367    }\r
368 #ifdef WIN32\r
369    else if(FrameFreeCount < FRAME_COUNT_SYNC)\r
370    {\r
371       FrameFree(frame);     //can't be ACK'ed\r
372    }\r
373 #endif\r
374    else\r
375    {\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
379    }\r
380 }\r
381 \r
382 \r
383 static void IPSendFrame(IPFrame *frame)\r
384 {\r
385    uint32 message[4];\r
386    int i;\r
387    unsigned char *packet=frame->packet;\r
388 \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
392    {\r
393       for(i = 0; i < sizeof(ArpCache) / sizeof(ArpCache_t); ++i)\r
394       {\r
395          if(memcmp(packet+IP_DEST, ArpCache[i].ip, 4) == 0)\r
396          {\r
397             memcpy(packet+ETHERNET_DEST, ArpCache[i].mac, 6);\r
398             if(frame->socket)\r
399                memcpy(frame->socket->headerSend+ETHERNET_DEST, ArpCache[i].mac, 6);\r
400             break;\r
401          }\r
402       }\r
403       if(packet[ETHERNET_DEST] == 0xff)\r
404          IPArp(packet+IP_DEST);\r
405    }\r
406 \r
407    if(FrameSendFunc)\r
408    {\r
409       //Single threaded\r
410       FrameSendFunc(frame->packet, frame->length);\r
411       IPFrameReschedule(frame);\r
412    }\r
413    else\r
414    {\r
415       //Add Packet to send queue\r
416       FrameInsert(&FrameSendHead, &FrameSendTail, frame);\r
417 \r
418       //Wakeup sender thread\r
419       message[0] = 2;\r
420       OS_MQueueSend(IPMQueue, message);\r
421    }\r
422 }\r
423 \r
424 \r
425 static void IPSendPacket(IPSocket *socket, IPFrame *frame, int length)\r
426 {\r
427    int checksum, length2=length;\r
428    unsigned char pseudo[12], *packet=frame->packet;\r
429 \r
430    frame->length = (uint16)length;\r
431 \r
432    //Calculate checksums\r
433    if(packet[ETHERNET_FRAME_TYPE+1] == 0x00)  //IP\r
434    {\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
443       {\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
448       }\r
449       else if(packet[IP_PROTOCOL] == 0x11)    //UDP\r
450       {\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
465       }\r
466       else if(packet[IP_PROTOCOL] == 0x06)    //TCP\r
467       {\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
481       }\r
482    }\r
483 \r
484    length2 = length - TCP_DATA;\r
485    if(socket && (packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN)))\r
486       length2 = 1;\r
487    frame->socket = socket;\r
488    frame->timeout = 0;\r
489    frame->retryCnt = 0;\r
490    if(socket)\r
491       frame->seqEnd = socket->seq + length2;\r
492    IPSendFrame(frame);\r
493 }\r
494 \r
495 \r
496 static void TCPSendPacket(IPSocket *socket, IPFrame *frame, int length)\r
497 {\r
498    uint8 *packet = frame->packet;\r
499    int flags, count;\r
500 \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
506    else\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
517    if(count < 0)\r
518       count = 0;\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
524 }\r
525 \r
526 \r
527 static void EthernetCreateResponse(unsigned char *packetOut,\r
528                                    const unsigned char *packet,\r
529                                    int length)\r
530 {\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
536    {\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
540       {\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
543       }\r
544    }\r
545 }\r
546 \r
547 \r
548 static void IPArp(unsigned char ipAddress[4])\r
549 {\r
550    IPFrame *frame;\r
551    uint8 *packetOut;\r
552 \r
553    frame = IPFrameGet(0);\r
554    if(frame == NULL)\r
555       return;\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
571 }\r
572 \r
573 \r
574 static void IPDhcp(const unsigned char *packet, int length, int state)\r
575 {\r
576    uint8 *packetOut, *ptr;\r
577    const uint8 *ptr2;\r
578    IPFrame *frame;\r
579    static int request=0;\r
580 \r
581    if(state == 1)\r
582    {\r
583       //Create DHCP Discover\r
584       frame = IPFrameGet(0);\r
585       if(frame == NULL)\r
586          return;\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
597    }\r
598    else if(state == 2 && memcmp(packet+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6) == 0)\r
599    {\r
600       if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_OFFER && request == DHCP_DISCOVER)\r
601       {\r
602          //Process DHCP Offer and send DHCP Request\r
603          frame = IPFrameGet(0);\r
604          if(frame == NULL)\r
605             return;\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
617          ptr[1] = 4;\r
618          memcpy(ptr+2, packet+DHCP_YOUR_IP, 4);\r
619          ptr[6] = DHCP_REQUEST_SERV_IP;\r
620          ptr[7] = 4;\r
621          memcpy(ptr+8, packet+DHCP_SERVER_IP, 4);\r
622          ptr[12] = DHCP_END_OPTION;\r
623          IPSendPacket(NULL, frame, 400);\r
624       }\r
625       else if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_ACK && request == DHCP_REQUEST)\r
626       {\r
627          //Process DHCP Ack\r
628          request = 0;\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
642          {\r
643             if(ptr2[0] == DHCP_PARAM_DNS)\r
644             {\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
647             }\r
648             ptr2 += ptr2[1] + 2;\r
649          }\r
650 \r
651          //Check if DHCP reply came from gateway\r
652          if(memcmp(packet+IP_SOURCE, ipAddressGateway, 4))\r
653          {\r
654             memset(ethernetAddressGateway, 0xff, 6);\r
655             IPArp(ipAddressGateway);     //Send ARP to gateway\r
656          }\r
657       }\r
658    }\r
659 }\r
660 \r
661 \r
662 uint32 IPAddressSelf(void)\r
663 {\r
664    return (ipAddressPlasma[0] << 24) | (ipAddressPlasma[1] << 16) |\r
665           (ipAddressPlasma[2] << 8) | ipAddressPlasma[3];\r
666 }\r
667 \r
668 \r
669 static int IPProcessTCPPacket(IPFrame *frameIn)\r
670 {\r
671    uint32 seq, ack;\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
676 \r
677    packet = frameIn->packet;\r
678    length = frameIn->length;\r
679 \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
685 \r
686    //Check if start of connection\r
687    if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == TCP_FLAGS_SYN)\r
688    {\r
689       if(IPVerbose)\r
690          printf("S");\r
691       //Check if duplicate SYN\r
692       for(socket = SocketHead; socket; socket = socket->next)\r
693       {\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
698          {\r
699             if(IPVerbose)\r
700                printf("s");\r
701             return 0;\r
702          }\r
703       }\r
704 \r
705       //Find an open port\r
706       for(socket = SocketHead; socket; socket = socket->next)\r
707       {\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
711          {\r
712             //Create a new socket\r
713             frameOut = IPFrameGet(FRAME_COUNT_SYNC);\r
714             if(frameOut == NULL)\r
715                return 0;\r
716             socketNew = (IPSocket*)malloc(sizeof(IPSocket));\r
717             if(socketNew == NULL)\r
718                return 0;\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
727 \r
728             //Send ACK\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
734             ++socketNew->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
740             ++socketNew->seq;\r
741 \r
742             //Add socket to linked list\r
743             OS_MutexPend(IPMutex);\r
744             socketNew->next = SocketHead;\r
745             socketNew->prev = NULL;\r
746             if(SocketHead)\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
752             return 0;\r
753          }\r
754       }\r
755 \r
756       //Send reset\r
757       frameOut = IPFrameGet(0);\r
758       if(frameOut == NULL)\r
759          return 0;\r
760       packetOut = frameOut->packet;\r
761       EthernetCreateResponse(packetOut, packet, TCP_DATA);\r
762       memset(packetOut+TCP_SEQ, 0, 4);\r
763       ++seq;\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
771       return 0;\r
772    }\r
773 \r
774    //Find an open socket\r
775    for(socket = SocketHead; socket; socket = socket->next)\r
776    {\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
780       {\r
781          break;\r
782       }\r
783    }\r
784    if(socket == NULL)\r
785    {\r
786       return 0;\r
787    }\r
788 \r
789    //Determine window\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
792 \r
793    //Check if packets can be removed from retransmition list\r
794    if(packet[TCP_FLAGS] & TCP_FLAGS_ACK)\r
795    {\r
796       if(ack != socket->seqReceived)\r
797       {\r
798          OS_MutexPend(IPMutex);\r
799          for(frame2 = FrameResendHead; frame2; )\r
800          {\r
801             framePrev = frame2;\r
802             frame2 = frame2->next;\r
803             if(framePrev->socket == socket && (int)(ack - framePrev->seqEnd) >= 0)\r
804             {\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
810             }\r
811          }\r
812          OS_MutexPost(IPMutex);\r
813          socket->seqReceived = ack;\r
814          socket->resentDone = 0;\r
815       }\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
819       {\r
820          //Detected that packet was lost, resend all\r
821          if(IPVerbose)\r
822             printf("A");\r
823          OS_MutexPend(IPMutex);\r
824          for(frame2 = FrameResendHead; frame2; )\r
825          {\r
826             framePrev = frame2;\r
827             frame2 = frame2->next;\r
828             if(framePrev->socket == socket)\r
829             {\r
830                //Remove packet from retransmition queue\r
831                FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);\r
832                IPSendFrame(framePrev);\r
833             }\r
834          }\r
835          OS_MutexPost(IPMutex);\r
836          socket->resentDone = 1;\r
837       }\r
838    }\r
839 \r
840    //Check if SYN/ACK\r
841    if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == \r
842       (TCP_FLAGS_SYN | TCP_FLAGS_ACK))\r
843    {\r
844       //Ack SYN/ACK\r
845       socket->ack = seq + 1;\r
846       socket->ackProcessed = seq + 1;\r
847       frameOut = IPFrameGet(FRAME_COUNT_SEND);\r
848       if(frameOut)\r
849       {\r
850          frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;\r
851          TCPSendPacket(socket, frameOut, TCP_DATA);\r
852       }\r
853       if(socket->funcPtr)\r
854          OS_Job(socket->funcPtr, socket, 0, 0);\r
855       return 0;\r
856    }\r
857    if(packet[TCP_HEADER_LENGTH] != 0x50)\r
858    {\r
859       if(IPVerbose)\r
860          printf("length error\n");\r
861       return 0;\r
862    }\r
863 \r
864    //Check if RST flag set\r
865    if(packet[TCP_FLAGS] & TCP_FLAGS_RST)\r
866    {\r
867       notify = 1;\r
868       IPClose2(socket);\r
869    }\r
870    //Copy packet into socket\r
871    else if(socket->ack == seq && bytes > 0)\r
872    {\r
873       //Insert packet into socket linked list\r
874       notify = 1;\r
875       if(socket->timeout)\r
876          socket->timeout = socket->timeoutReset;\r
877       if(IPVerbose)\r
878          printf("D");\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
883 \r
884       //Ack data\r
885       frameOut = IPFrameGet(FRAME_COUNT_SEND);\r
886       if(frameOut)\r
887       {\r
888          frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;\r
889          TCPSendPacket(socket, frameOut, TCP_DATA);\r
890       }\r
891 \r
892       //Using frame\r
893       rc = 1;\r
894    }\r
895    else if(bytes)\r
896    {\r
897       //Ack with current offset since data missing\r
898       frameOut = IPFrameGet(FRAME_COUNT_SEND);\r
899       if(frameOut)\r
900       {\r
901          frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK;\r
902          TCPSendPacket(socket, frameOut, TCP_DATA);\r
903       }\r
904    }\r
905 \r
906    //Check if FIN flag set\r
907    if(packet[TCP_FLAGS] & TCP_FLAGS_FIN && socket->ack >= seq)\r
908    {\r
909       notify = 1;\r
910       socket->timeout = SOCKET_TIMEOUT;\r
911       if(IPVerbose)\r
912          printf("F");\r
913       frameOut = IPFrameGet(0);\r
914       if(frameOut == NULL)\r
915          return 0;\r
916       packetOut = frameOut->packet;\r
917       packetOut[TCP_FLAGS] = TCP_FLAGS_ACK;\r
918       ++socket->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
924    }\r
925 \r
926    //Notify application\r
927    if(socket->funcPtr && notify)\r
928       OS_Job(socket->funcPtr, socket, 0, 0);\r
929    return rc;\r
930 }\r
931 \r
932 \r
933 int IPProcessEthernetPacket(IPFrame *frameIn, int length)\r
934 {\r
935    int ip_length, rc;\r
936    IPSocket *socket;\r
937    IPFrame *frameOut;\r
938    uint8 *packet, *packetOut;\r
939 \r
940    packet = frameIn->packet;\r
941    frameIn->length = (uint16)length;\r
942 \r
943    if(packet[ETHERNET_FRAME_TYPE] != 0x08 || frameIn->length > PACKET_SIZE)\r
944       return 0;  //wrong ethernet type, packet not used\r
945 \r
946    //ARP?\r
947    if(packet[ETHERNET_FRAME_TYPE+1] == 0x06)\r
948    {\r
949       //Check if ARP reply\r
950       if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) == 0 &&\r
951          packet[ARP_OP+1] == 2)\r
952       {\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
956             ArpCacheIndex = 0;\r
957          if(memcmp(packet+ARP_IP_SENDER, ipAddressGateway, 4) == 0)\r
958          {\r
959             //Found MAC address for gateway\r
960             memcpy(ethernetAddressGateway, packet+ARP_ETHERNET_SENDER, 6);\r
961          }\r
962          return 0;\r
963       }\r
964 \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
968          return 0;\r
969       //Create ARP response\r
970       frameOut = IPFrameGet(0);\r
971       if(frameOut == NULL)\r
972          return 0;\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
983       return 0;\r
984    }\r
985 \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
989       return 0;\r
990    if(packet[ETHERNET_FRAME_TYPE+1] != 0x00 ||\r
991       packet[IP_VERSION_LENGTH] != 0x45)\r
992       return 0;\r
993 \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
998    {\r
999       IPDhcp(packet, frameIn->length, 2);            //DHCP reply\r
1000       return 0;\r
1001    }\r
1002 \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
1006       return 0;\r
1007    rc = EthernetVerifyChecksums(packet, frameIn->length);\r
1008 #ifndef WIN32\r
1009    if(rc && FrameSendFunc)\r
1010    {\r
1011       printf("C ");\r
1012       return 0;\r
1013    }\r
1014 #endif\r
1015 \r
1016    //PING request?\r
1017    if(packet[IP_PROTOCOL] == 1)\r
1018    {\r
1019       if(packet[PING_TYPE] == 0)  //PING reply\r
1020       {\r
1021          for(socket = SocketHead; socket; socket = socket->next)\r
1022          {\r
1023             if(socket->state == IP_PING && \r
1024                memcmp(packet+IP_SOURCE, socket->headerSend+IP_DEST, 4) == 0)\r
1025             {\r
1026                OS_Job(socket->funcPtr, socket, 0, 0);\r
1027                return 0;\r
1028             }\r
1029          }\r
1030       }\r
1031       if(packet[PING_TYPE] != 8)\r
1032          return 0;\r
1033       frameOut = IPFrameGet(FRAME_COUNT_SEND);\r
1034       if(frameOut == NULL)\r
1035          return 0;\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
1040       return 0;\r
1041    }\r
1042 \r
1043    //TCP packet?\r
1044    if(packet[IP_PROTOCOL] == 0x06)\r
1045    {\r
1046       return IPProcessTCPPacket(frameIn);\r
1047    }\r
1048 \r
1049    //UDP packet?\r
1050    if(packet[IP_PROTOCOL] == 0x11)\r
1051    {\r
1052       //Find open socket\r
1053       for(socket = SocketHead; socket; socket = socket->next)\r
1054       {\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
1058          {\r
1059             break;\r
1060          }\r
1061       }\r
1062 \r
1063       if(socket == NULL)\r
1064       {\r
1065          //Find listening socket\r
1066          for(socket = SocketHead; socket; socket = socket->next)\r
1067          {\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
1070             {\r
1071                EthernetCreateResponse(socket->headerSend, packet, UDP_DATA);\r
1072                break;\r
1073             }\r
1074          }\r
1075       }\r
1076 \r
1077       if(socket)\r
1078       {\r
1079          if(IPVerbose)\r
1080             printf("U");\r
1081          FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn);\r
1082          OS_Job(socket->funcPtr, socket, 0, 0);\r
1083          return 1;\r
1084       }\r
1085    }\r
1086    return 0;\r
1087 }\r
1088 \r
1089 \r
1090 #ifndef WIN32\r
1091 static void IPMainThread(void *arg)\r
1092 {\r
1093    uint32 message[4];\r
1094    int rc;\r
1095    IPFrame *frame, *frameOut=NULL;\r
1096    uint32 ticks, ticksLast;\r
1097    (void)arg;\r
1098 \r
1099    ticksLast = OS_ThreadTime();\r
1100    memset(message, 0, sizeof(message));\r
1101 \r
1102    for(;;)\r
1103    {\r
1104       Led(7, 0);\r
1105       rc = OS_MQueueGet(IPMQueue, message, 10);\r
1106       if(rc == 0)\r
1107       {\r
1108          frame = (IPFrame*)message[1];\r
1109          if(message[0] == 0)       //frame received\r
1110          {\r
1111             Led(7, 1);\r
1112             frame->length = (uint16)message[2];\r
1113             rc = IPProcessEthernetPacket(frame, frame->length);\r
1114             if(rc == 0)\r
1115                FrameFree(frame);\r
1116          }\r
1117          else if(message[0] == 1)  //frame sent\r
1118          {\r
1119             Led(7, 2);\r
1120             assert(frame == frameOut);\r
1121             IPFrameReschedule(frame);\r
1122             frameOut = NULL;\r
1123          }\r
1124          else if(message[0] == 2)  //frame ready to send\r
1125          {\r
1126          }\r
1127       }\r
1128 \r
1129       if(frameOut == NULL)\r
1130       {\r
1131          OS_MutexPend(IPMutex);\r
1132          frameOut = FrameSendTail;\r
1133          if(frameOut)\r
1134             FrameRemove(&FrameSendHead, &FrameSendTail, frameOut);\r
1135          OS_MutexPost(IPMutex);\r
1136          if(frameOut)\r
1137          {\r
1138             Led(7, 4);\r
1139             UartPacketSend(frameOut->packet, frameOut->length);\r
1140          }\r
1141       }\r
1142 \r
1143       ticks = OS_ThreadTime();\r
1144       if(ticks - ticksLast > 100)\r
1145       {\r
1146          IPTick();\r
1147          ticksLast = ticks;\r
1148       }\r
1149    }\r
1150 }\r
1151 #endif\r
1152 \r
1153 \r
1154 uint8 *MyPacketGet(void)\r
1155 {\r
1156    return (uint8*)IPFrameGet(FRAME_COUNT_RCV);\r
1157 }\r
1158 \r
1159 \r
1160 //Set FrameSendFunction only if single threaded\r
1161 void IPInit(IPFuncPtr frameSendFunction, uint8 macAddress[6], char name[6])\r
1162 {\r
1163    int i;\r
1164    IPFrame *frame;\r
1165 \r
1166    if(macAddress)\r
1167       memcpy(ethernetAddressPlasma, macAddress, 6);\r
1168    if(name)\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
1174    {\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
1180    }\r
1181    FrameFreeCount = FRAME_COUNT;\r
1182 #ifndef WIN32\r
1183    UartPacketConfig(MyPacketGet, PACKET_SIZE, IPMQueue);\r
1184    if(frameSendFunction == NULL)\r
1185       IPThread = OS_ThreadCreate("TCP/IP", IPMainThread, NULL, 240, 6000);\r
1186 #endif\r
1187    IPDhcp(NULL, 360, 1);        //Send DHCP request\r
1188 }\r
1189 \r
1190 \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
1193 {\r
1194    IPSocket *socket;\r
1195    uint8 *ptrSend, *ptrRcv;\r
1196    IPFrame *frame;\r
1197    static int portSource=0x1007;\r
1198 \r
1199    socket = (IPSocket*)malloc(sizeof(IPSocket));\r
1200    if(socket == NULL)\r
1201       return socket;\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
1217 \r
1218    if(ipAddress == 0)\r
1219    {\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
1223    }\r
1224    else\r
1225    {\r
1226       //Setup sending packet\r
1227       memset(ptrSend, 0, UDP_LENGTH);\r
1228       memset(ptrRcv, 0, UDP_LENGTH);\r
1229 \r
1230       //Setup Ethernet\r
1231       if(ipAddress != IPAddressSelf())\r
1232          memcpy(ptrSend+ETHERNET_DEST, ethernetAddressGateway, 6);\r
1233       else\r
1234          memcpy(ptrSend+ETHERNET_DEST, ethernetAddressPlasma, 6);\r
1235       memcpy(ptrSend+ETHERNET_SOURCE, ethernetAddressPlasma, 6);\r
1236       ptrSend[ETHERNET_FRAME_TYPE] = 0x08;\r
1237 \r
1238       //Setup IP\r
1239       ptrSend[IP_VERSION_LENGTH] = 0x45;\r
1240       ptrSend[IP_TIME_TO_LIVE] = 0x80;\r
1241 \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
1253 \r
1254       //Setup ports\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
1263       ++portSource;\r
1264    }\r
1265 \r
1266    if(mode == IP_MODE_TCP)\r
1267    {\r
1268       if(ipAddress)\r
1269          socket->state = IP_TCP;\r
1270       else\r
1271          socket->state = IP_LISTEN;\r
1272       ptrSend[IP_PROTOCOL] = 0x06;  //TCP\r
1273       ptrRcv[IP_PROTOCOL] = 0x06;\r
1274    }\r
1275    else if(mode == IP_MODE_UDP)\r
1276    {\r
1277       socket->state = IP_UDP;\r
1278       ptrSend[IP_PROTOCOL] = 0x11;  //UDP\r
1279       ptrRcv[IP_PROTOCOL] = 0x11; \r
1280    }\r
1281    else if(mode == IP_MODE_PING)\r
1282    {\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
1287    }\r
1288 \r
1289    //Add socket to linked list\r
1290    OS_MutexPend(IPMutex);\r
1291    socket->next = SocketHead;\r
1292    socket->prev = NULL;\r
1293    if(SocketHead)\r
1294       SocketHead->prev = socket;\r
1295    SocketHead = socket;\r
1296    OS_MutexPost(IPMutex);\r
1297 \r
1298    if(mode == IP_MODE_TCP && ipAddress)\r
1299    {\r
1300       //Send TCP SYN\r
1301       socket->seq = 0x01234567;\r
1302       frame = IPFrameGet(0);\r
1303       if(frame)\r
1304       {\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
1311          ++socket->seq;\r
1312       }\r
1313    }\r
1314    return socket;\r
1315 }\r
1316 \r
1317 \r
1318 void IPWriteFlush(IPSocket *socket)\r
1319 {\r
1320    uint8 *packetOut;\r
1321    if(socket->frameSend && socket->state != IP_UDP &&\r
1322       socket->state != IP_PING)\r
1323    {\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
1330    }\r
1331 }\r
1332 \r
1333 \r
1334 uint32 IPWrite(IPSocket *socket, const uint8 *buf, uint32 length)\r
1335 {\r
1336    IPFrame *frameOut;\r
1337    uint8 *packetOut;\r
1338    uint32 bytes, count=0, tries=0;\r
1339    int offset;\r
1340    OS_Thread_t *self;\r
1341 \r
1342    if(socket->state > IP_TCP)\r
1343       return 0;\r
1344 \r
1345    if(socket->timeout)\r
1346       socket->timeout = socket->timeoutReset;\r
1347 \r
1348 #ifdef INCLUDE_FILESYS\r
1349    if(socket->fileOut)   //override stdout\r
1350       return fwrite((char*)buf, 1, length, socket->fileOut);\r
1351 #endif\r
1352  \r
1353    //printf("IPWrite(0x%x, %d)", Socket, Length);\r
1354    self = OS_ThreadSelf();\r
1355    while(length)\r
1356    {\r
1357       //Rate limit output\r
1358       if(socket->seq - socket->seqReceived >= SEND_WINDOW)\r
1359       {\r
1360          //printf("l(%d,%d,%d) ", socket->seq - socket->seqReceived, socket->seq, socket->seqReceived);\r
1361          if(self != IPThread && ++tries < 200)\r
1362          {\r
1363             OS_ThreadSleep(1);\r
1364             continue;\r
1365          }\r
1366       }\r
1367       tries = 0;\r
1368       while(socket->frameSend == NULL)\r
1369       {\r
1370          socket->frameSend = IPFrameGet(FRAME_COUNT_SEND);\r
1371          socket->sendOffset = 0;\r
1372          if(socket->frameSend == NULL)\r
1373          {\r
1374             //printf("L");\r
1375             if(self == IPThread || ++tries > 200)\r
1376                break;\r
1377             else\r
1378                OS_ThreadSleep(1);\r
1379          }\r
1380       }\r
1381       frameOut = socket->frameSend;\r
1382       offset = socket->sendOffset;\r
1383       if(frameOut == NULL)\r
1384          break;\r
1385       packetOut = frameOut->packet;\r
1386 \r
1387       if(socket->state == IP_PING)\r
1388       {\r
1389          bytes = length;\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
1394       }\r
1395       else if(socket->state != IP_UDP)\r
1396       {\r
1397          bytes = 512 - offset;\r
1398          if(bytes > length)\r
1399             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
1405          //{\r
1406          //   printf("W");\r
1407          //   OS_ThreadSleep(10);\r
1408          //}\r
1409       }\r
1410       else  //UDP\r
1411       {\r
1412          bytes = length;\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
1417       }\r
1418       count += bytes;\r
1419       buf += bytes;\r
1420       length -= bytes;\r
1421    }\r
1422    return count;\r
1423 }\r
1424 \r
1425 \r
1426 uint32 IPRead(IPSocket *socket, uint8 *buf, uint32 length)\r
1427 {\r
1428    IPFrame *frame, *frame2;\r
1429    int count=0, bytes, offset;\r
1430 \r
1431 #ifdef INCLUDE_FILESYS\r
1432    if(socket->fileIn)   //override stdin\r
1433    {\r
1434       bytes = fread(buf, 1, 1, socket->fileIn);\r
1435       if(bytes == 0)\r
1436       {\r
1437          buf[0] = 0;\r
1438          fclose(socket->fileIn);\r
1439          socket->fileIn = NULL;\r
1440          bytes = 1;\r
1441       }\r
1442       return bytes;\r
1443    }\r
1444 #endif\r
1445 \r
1446    if(socket->state == IP_UDP)\r
1447       offset = UDP_DATA;\r
1448    else\r
1449       offset = TCP_DATA;\r
1450 \r
1451    OS_MutexPend(IPMutex);\r
1452    for(frame = socket->frameReadTail; length && frame; )\r
1453    {\r
1454       bytes = frame->length - offset - socket->readOffset;\r
1455       if(bytes > (int)length)\r
1456          bytes = length;\r
1457       memcpy(buf, frame->packet + offset + socket->readOffset, bytes);\r
1458       buf += bytes;\r
1459       socket->readOffset += bytes;\r
1460       length -= bytes;\r
1461       count += bytes;\r
1462 \r
1463       //Check if done with packet\r
1464       frame2 = frame;\r
1465       frame = frame->prev;\r
1466       if(socket->readOffset == frame2->length - offset)\r
1467       {\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
1474          {\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
1478          }\r
1479          else\r
1480             FrameFree(frame2);\r
1481       }\r
1482    }\r
1483    OS_MutexPost(IPMutex);\r
1484    return count;\r
1485 }\r
1486 \r
1487 \r
1488 static void IPClose2(IPSocket *socket)\r
1489 {\r
1490    IPFrame *frame, *framePrev;\r
1491 \r
1492    //printf("IPClose2(%x) ", (int)socket);\r
1493 \r
1494    OS_MutexPend(IPMutex);\r
1495 \r
1496    //Remove pending packets\r
1497    for(frame = FrameSendHead; frame; )\r
1498    {\r
1499       framePrev = frame;\r
1500       frame = frame->next;\r
1501       if(framePrev->socket == socket)\r
1502       {\r
1503          FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);\r
1504          FrameFree(framePrev);\r
1505       }\r
1506    }\r
1507 \r
1508    //Remove packets from retransmision list\r
1509    for(frame = FrameResendHead; frame; )\r
1510    {\r
1511       framePrev = frame;\r
1512       frame = frame->next;\r
1513       if(framePrev->socket == socket)\r
1514       {\r
1515          FrameRemove(&FrameResendHead, &FrameResendTail, framePrev);\r
1516          FrameFree(framePrev);\r
1517       }\r
1518    }\r
1519 \r
1520    //Remove packets from socket read linked list\r
1521    for(frame = socket->frameReadHead; frame; )\r
1522    {\r
1523       framePrev = frame;\r
1524       frame = frame->next;\r
1525       FrameRemove(&socket->frameReadHead, &socket->frameReadTail, framePrev);\r
1526       FrameFree(framePrev);\r
1527    }\r
1528 \r
1529    //Give application time to stop using socket\r
1530    socket->timeout = SOCKET_TIMEOUT;\r
1531    socket->state = IP_CLOSED;\r
1532 \r
1533    OS_MutexPost(IPMutex);\r
1534 }\r
1535 \r
1536 \r
1537 void IPClose(IPSocket *socket)\r
1538 {\r
1539    IPFrame *frameOut;\r
1540 \r
1541    //printf("IPClose(%x) ", (int)socket);\r
1542 \r
1543    IPWriteFlush(socket);\r
1544    if(socket->state <= IP_UDP)\r
1545    {\r
1546       IPClose2(socket);\r
1547       return;\r
1548    }\r
1549    frameOut = IPFrameGet(0);\r
1550    if(frameOut == NULL)\r
1551       return;\r
1552    frameOut->packet[TCP_FLAGS] = TCP_FLAGS_FIN | TCP_FLAGS_ACK;\r
1553    TCPSendPacket(socket, frameOut, TCP_DATA);\r
1554    ++socket->seq;\r
1555    socket->timeout = SOCKET_TIMEOUT;\r
1556    socket->timeoutReset = SOCKET_TIMEOUT;\r
1557    socket->state = IP_FIN_SERVER;\r
1558 }\r
1559 \r
1560 \r
1561 void IPPrintf(IPSocket *socket, char *message, \r
1562               int arg0, int arg1, int arg2, int arg3)\r
1563 {\r
1564    char buf[500];\r
1565    if(socket == NULL)\r
1566    {\r
1567       printf(message, arg0, arg1, arg2, arg3);\r
1568       return;\r
1569    }\r
1570    if(strcmp(message, "%s") == 0)\r
1571       IPWrite(socket, (uint8*)arg0, (int)strlen((char*)arg0));\r
1572    else\r
1573    {\r
1574       sprintf(buf, message, arg0, arg1, arg2, arg3, 0, 0, 0, 0);\r
1575       IPWrite(socket, (uint8*)buf, (int)strlen(buf));\r
1576    }\r
1577    if(socket->dontFlush == 0 || strstr(message, "\n"))\r
1578       IPWriteFlush(socket);\r
1579 }\r
1580 \r
1581 \r
1582 void IPTick(void)\r
1583 {\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
1588 \r
1589    ticks = OS_ThreadTime();\r
1590 #ifdef WIN32\r
1591    ticks = ticksPrev + 100;\r
1592 #endif\r
1593    if(ticks - ticksPrev >= 95)\r
1594    {\r
1595       if(IPVerbose && (Seconds % 60) == 0)\r
1596       {\r
1597          if(FrameFreeCount >= FRAME_COUNT-1)\r
1598             printf("T");\r
1599          else\r
1600             printf("T(%d)", FrameFreeCount);\r
1601       }\r
1602       ++Seconds;\r
1603       if(--DhcpRetrySeconds <= 0)\r
1604          IPDhcp(NULL, 400, 1);   //DHCP request\r
1605    }\r
1606 \r
1607    OS_MutexPend(IPMutex);\r
1608 \r
1609    //Retransmit timeout packets\r
1610    for(frame = FrameResendHead; frame; )\r
1611    {\r
1612       frame2 = frame;\r
1613       frame = frame->next;\r
1614       frame2->timeout = (short)(frame2->timeout - (ticks - ticksPrev2));\r
1615       if(--frame2->timeout <= 0)\r
1616       {\r
1617          if(IPVerbose)\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
1624          else \r
1625          {\r
1626             if(frame2->socket->state == IP_TCP)\r
1627                IPClose(frame2->socket);\r
1628             FrameFree(frame2);\r
1629          }\r
1630       }\r
1631    }\r
1632 \r
1633    if(ticks - ticksPrev >= 95)\r
1634    {\r
1635       //Close timed out sockets\r
1636       for(socket = SocketHead; socket; )\r
1637       {\r
1638          socket2 = socket;\r
1639          socket = socket->next;\r
1640          if(socket2->timeout && --socket2->timeout == 0)\r
1641          {\r
1642             socket2->timeout = SOCKET_TIMEOUT;\r
1643             if(socket2->state <= IP_TCP || socket2->state == IP_FIN_CLIENT)\r
1644                IPClose(socket2);\r
1645             else if(socket2->state != IP_CLOSED)\r
1646                IPClose2(socket2);\r
1647             else\r
1648             {\r
1649                if(socket2->prev == NULL)\r
1650                   SocketHead = socket2->next;\r
1651                else\r
1652                   socket2->prev->next = socket2->next;\r
1653                if(socket2->next)\r
1654                   socket2->next->prev = socket2->prev;\r
1655                //printf("freeSocket(%x) ", (int)socket2);\r
1656                free(socket2);\r
1657             }\r
1658          }\r
1659       }\r
1660       ticksPrev = ticks;\r
1661    }\r
1662    OS_MutexPost(IPMutex);\r
1663    ticksPrev2 = ticks;\r
1664 }\r
1665 \r
1666 \r
1667 static void DnsCallback(IPSocket *socket)\r
1668 {\r
1669    uint8 buf[200], *ptr;\r
1670    uint32 ipAddress;\r
1671    int bytes;\r
1672 \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
1676    {\r
1677       for(ptr = buf + DNS_QUESTIONS; ptr + 14 <= buf + bytes; ++ptr)\r
1678       {\r
1679          if(ptr[0] == 0 && ptr[1] == 1 && ptr[2] == 0 && ptr[3] == 1 && \r
1680             ptr[8] == 0 && ptr[9] == 4)\r
1681          {\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
1686             {\r
1687                socket->userFunc(socket, ipAddress, socket->userPtr);\r
1688             }\r
1689             break;\r
1690          }\r
1691       }\r
1692    }\r
1693    IPClose(socket);\r
1694 }\r
1695 \r
1696 \r
1697 void IPResolve(char *name, IPFuncPtr resolvedFunc, void *arg)\r
1698 {\r
1699    uint8 buf[200], *ptr;\r
1700    int length, i;\r
1701    IPSocket *socket;\r
1702 \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
1708 \r
1709    //Setup name\r
1710    ptr = buf + DNS_QUESTIONS;\r
1711    strncpy((char*)ptr+1, name, 100);\r
1712    ptr[0] = 1;\r
1713    while(ptr[0])\r
1714    {\r
1715       for(i = 0; i < 100; ++i)\r
1716       {\r
1717          if(ptr[i+1] == '.' || ptr[i+1] == 0)\r
1718          {\r
1719             ptr[0] = (uint8)i;\r
1720             ptr += i+1;\r
1721             break;\r
1722          }\r
1723       }\r
1724    }\r
1725    ++ptr;\r
1726    ptr[1] = DNS_QUERY_TYPE_IP;\r
1727    ptr[3] = DNS_QUERY_CLASS;\r
1728    length = (int)(ptr - buf) + 4;\r
1729    if(length < 60)\r
1730       length = 60;\r
1731 \r
1732    socket->userFunc = (IPFuncPtr)resolvedFunc;\r
1733    socket->userPtr = arg;\r
1734    socket->userData = 0;\r
1735    IPWrite(socket, buf, length);\r
1736 }\r
1737 \r