root/webserver/example/EasyWEB/tcpip.c

Revision 9, 35.6 kB (checked in by phil, 15 years ago)

EasyWEB example for uVision (original from CD)

Line 
1 /******************************************************************
2  *****                                                        *****
3  *****  Name: tcpip.c                                         *****
4  *****  Ver.: 1.0                                             *****
5  *****  Date: 07/05/2001                                      *****
6  *****  Auth: Andreas Dannenberg                              *****
7  *****        HTWK Leipzig                                    *****
8  *****        university of applied sciences                  *****
9  *****        Germany                                         *****
10  *****  Func: implements the TCP/IP-stack and provides a      *****
11  *****        simple API to the user                          *****
12  *****                                                        *****
13  ******************************************************************/
14
15 #include "tcpip.h"
16 #include "EMAC.h"       
17 #include <string.h>       
18 #include <LPC23xx.h>     
19
20 const unsigned char MyMAC[6] =   // "M1-M2-M3-M4-M5-M6"
21 {
22   MYMAC_1, MYMAC_2, MYMAC_3,
23   MYMAC_4, MYMAC_5, MYMAC_6
24 };
25
26 // easyWEB-API function
27 // initalizes the LAN-controller, reset flags, starts timer-ISR
28
29 void TCPLowLevelInit(void)
30 {
31 // Keil: Timer 0 is used for TCP retransmission control
32   T0MR0 = 3144000;                                      // 262mSec
33   T0MCR = 3;                                            // Interrupt and Reset on MR0
34   T0TCR = 1;                                            // Timer0 Enable
35   VICVectAddr4 = (unsigned int)TCPClockHandler;         // set interrupt vector in 4
36   VICIntEnable = 0x00000010;                            // Enable Timer0 Interrupt
37  
38   Init_EMAC();
39   TransmitControl = 0;
40   TCPFlags = 0;
41   TCPStateMachine = CLOSED;
42   SocketStatus = 0;
43 }
44
45 // easyWEB-API function
46 // does a passive open (listen on 'MyIP:TCPLocalPort' for an incoming
47 // connection)
48
49 void TCPPassiveOpen(void)
50 {
51   if (TCPStateMachine == CLOSED)
52   {
53     TCPFlags &= ~TCP_ACTIVE_OPEN;                // let's do a passive open!
54     TCPStateMachine = LISTENING;
55     SocketStatus = SOCK_ACTIVE;                  // reset, socket now active
56   }
57 }
58
59 // easyWEB-API function
60 // does an active open (tries to establish a connection between
61 // 'MyIP:TCPLocalPort' and 'RemoteIP:TCPRemotePort')
62
63 void TCPActiveOpen(void)
64 {
65   if ((TCPStateMachine == CLOSED) || (TCPStateMachine == LISTENING))
66   {
67     TCPFlags |= TCP_ACTIVE_OPEN;                 // let's do an active open!
68     TCPFlags &= ~IP_ADDR_RESOLVED;               // we haven't opponents MAC yet
69  
70     PrepareARP_REQUEST();                        // ask for MAC by sending a broadcast
71     LastFrameSent = ARP_REQUEST;
72     TCPStartRetryTimer();
73     SocketStatus = SOCK_ACTIVE;                  // reset, socket now active   
74   }
75 }
76
77 // easyWEB-API function
78 // closes an open connection
79
80 void TCPClose(void)
81 {
82   switch (TCPStateMachine)
83   {
84     case LISTENING :
85     case SYN_SENT :
86     {
87       TCPStateMachine = CLOSED;
88       TCPFlags = 0;
89       SocketStatus = 0;
90       break;
91     }
92     case SYN_RECD :
93     case ESTABLISHED :
94     {
95       TCPFlags |= TCP_CLOSE_REQUESTED;
96       break;
97     }
98   }
99 }
100
101 // easyWEB-API function
102 // releases the receive-buffer and allows easyWEB to store new data
103 // NOTE: rx-buffer MUST be released periodically, else the other TCP
104 //       get no ACKs for the data it sent
105
106 void TCPReleaseRxBuffer(void)
107 {
108   SocketStatus &= ~SOCK_DATA_AVAILABLE;
109 }
110
111 // easyWEB-API function
112 // transmitts data stored in 'TCP_TX_BUF'
113 // NOTE: * number of bytes to transmit must have been written to 'TCPTxDataCount'
114 //       * data-count MUST NOT exceed 'MAX_TCP_TX_DATA_SIZE'
115
116 void TCPTransmitTxBuffer(void)
117 {
118   if ((TCPStateMachine == ESTABLISHED) || (TCPStateMachine == CLOSE_WAIT))
119     if (SocketStatus & SOCK_TX_BUF_RELEASED)
120     {
121       SocketStatus &= ~SOCK_TX_BUF_RELEASED;               // occupy tx-buffer
122       TCPUNASeqNr += TCPTxDataCount;                       // advance UNA
123      
124       TxFrame1Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE + TCPTxDataCount;
125       TransmitControl |= SEND_FRAME1;
126      
127       LastFrameSent = TCP_DATA_FRAME;
128       TCPStartRetryTimer();
129     }
130 }
131
132 // Reads the length of the received ethernet frame and checks if the
133 // destination address is a broadcast message or not
134 unsigned int IsBroadcast(void) {
135   unsigned short RecdDestMAC[3];         // 48 bit MAC
136
137   RecdFrameLength = StartReadFrame();
138
139   CopyFromFrame_EMAC(&RecdDestMAC,  6);           // receive DA to see if it was a broadcast
140   CopyFromFrame_EMAC(&RecdFrameMAC, 6);           // store SA (for our answer)
141
142   if ((RecdDestMAC[0] == 0xFFFF) &&
143       (RecdDestMAC[1] == 0xFFFF) &&
144       (RecdDestMAC[2] == 0xFFFF)) {
145     return(1);
146   } else {
147     return (0);
148   }
149 }
150
151
152 // easyWEB's 'main()'-function
153 // must be called from user program periodically (the often - the better)
154 // handles network, TCP/IP-stack and user events
155
156 void DoNetworkStuff(void)
157 {
158   if (CheckFrameReceived())                      // Packet received
159   {
160     if (IsBroadcast()) {
161       ProcessEthBroadcastFrame();
162     } else {
163       ProcessEthIAFrame();
164     }
165     EndReadFrame();                              // release buffer in ethernet controller
166
167         // Active Process Frame Status //
168     //LED2_OFF();                                                                       // Status Frame Process Ready
169         //FIO3SET = 0x04000000;                         // OFF LED2
170   }
171
172   if (TCPFlags & TCP_TIMER_RUNNING)
173     if (TCPFlags & TIMER_TYPE_RETRY)
174     {
175       if (TCPTimer > RETRY_TIMEOUT)
176       {
177         TCPRestartTimer();                       // set a new timeout
178
179         if (RetryCounter)
180         {
181           TCPHandleRetransmission();             // resend last frame
182           RetryCounter--;
183         }
184         else
185         {
186           TCPStopTimer();
187           TCPHandleTimeout();
188         }
189       }
190     }
191     else if (TCPTimer > FIN_TIMEOUT)
192     {
193       TCPStateMachine = CLOSED;
194       TCPFlags = 0;                              // reset all flags, stop retransmission...
195       SocketStatus &= SOCK_DATA_AVAILABLE;       // clear all flags but data available
196     }
197
198   switch (TCPStateMachine)
199   {
200     case CLOSED :
201     case LISTENING :
202     {
203       if (TCPFlags & TCP_ACTIVE_OPEN)            // stack has to open a connection?
204         if (TCPFlags & IP_ADDR_RESOLVED)         // IP resolved?
205           if (!(TransmitControl & SEND_FRAME2))  // buffer free?
206           {
207             TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (T0TC & 0xFFFF);  // Keil: changed from TAR to T0TC;
208                                                                 // set local ISN
209             TCPUNASeqNr = TCPSeqNr;
210             TCPAckNr = 0;                                       // we don't know what to ACK!
211             TCPUNASeqNr++;                                      // count SYN as a byte
212             PrepareTCP_FRAME(TCP_CODE_SYN);                     // send SYN frame
213             LastFrameSent = TCP_SYN_FRAME;
214             TCPStartRetryTimer();                               // we NEED a retry-timeout
215             TCPStateMachine = SYN_SENT;
216           }
217       break;
218     }
219     case SYN_RECD :
220     case ESTABLISHED :
221     {
222       if (TCPFlags & TCP_CLOSE_REQUESTED)                  // user has user initated a close?
223         if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1)))   // buffers free?
224           if (TCPSeqNr == TCPUNASeqNr)                          // all data ACKed?
225           {
226             TCPUNASeqNr++;
227             PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK);
228             LastFrameSent = TCP_FIN_FRAME;
229             TCPStartRetryTimer();
230             TCPStateMachine = FIN_WAIT_1;
231           }
232       break;
233     }
234     case CLOSE_WAIT :
235     {
236       if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1)))     // buffers free?
237         if (TCPSeqNr == TCPUNASeqNr)                            // all data ACKed?
238         {
239           TCPUNASeqNr++;                                        // count FIN as a byte
240           PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK);        // we NEED a retry-timeout
241           LastFrameSent = TCP_FIN_FRAME;                        // time to say goodbye...
242           TCPStartRetryTimer();
243           TCPStateMachine = LAST_ACK;
244         }
245       break;
246     }
247   }
248
249   if (TransmitControl & SEND_FRAME2)
250   {
251     RequestSend(TxFrame2Size);
252
253     if (Rdy4Tx())                                // NOTE: when using a very fast MCU, maybe
254       SendFrame2();                              // the EMAC isn't ready yet, include
255     else {                                       // a kind of timer or counter here
256       TCPStateMachine = CLOSED;
257       SocketStatus = SOCK_ERR_ETHERNET;          // indicate an error to user
258       TCPFlags = 0;                              // clear all flags, stop timers etc.
259     }
260
261     TransmitControl &= ~SEND_FRAME2;             // clear tx-flag
262   }
263
264   if (TransmitControl & SEND_FRAME1)
265   {
266     PrepareTCP_DATA_FRAME();                     // build frame w/ actual SEQ, ACK....
267     RequestSend(TxFrame1Size);
268  
269     if (Rdy4Tx())                                // EMAC ready to accept our frame?
270       SendFrame1();                              // (see note above)
271     else {
272       TCPStateMachine = CLOSED;
273       SocketStatus = SOCK_ERR_ETHERNET;          // indicate an error to user
274       TCPFlags = 0;                              // clear all flags, stop timers etc.
275     }
276
277     TransmitControl &= ~SEND_FRAME1;             // clear tx-flag
278   }
279 }
280
281 // easyWEB internal function
282 // handles an incoming broadcast frame
283
284 void ProcessEthBroadcastFrame(void)
285 {
286   unsigned short TargetIP[2];
287
288   if (ReadFrameBE_EMAC() == FRAME_ARP)           // get frame type, check for ARP
289     if (ReadFrameBE_EMAC() == HARDW_ETH10)       // Ethernet frame
290       if (ReadFrameBE_EMAC() == FRAME_IP)        // check protocol
291         if (ReadFrameBE_EMAC() == IP_HLEN_PLEN)  // check HLEN, PLEN
292           if (ReadFrameBE_EMAC() == OP_ARP_REQUEST)
293           {
294             DummyReadFrame_EMAC(6);              // ignore sender's hardware address
295             CopyFromFrame_EMAC(&RecdFrameIP, 4); // read sender's protocol address
296             DummyReadFrame_EMAC(6);              // ignore target's hardware address
297             CopyFromFrame_EMAC(&TargetIP, 4);    // read target's protocol address
298             if (!memcmp(&MyIP, &TargetIP, 4))    // is it for us?
299               PrepareARP_ANSWER();               // yes->create ARP_ANSWER frame
300           }
301 }
302
303 // easyWEB internal function
304 // handles an incoming frame that passed EMAC's address filter
305 // (individual addressed = IA)
306
307 void ProcessEthIAFrame(void)
308 {
309   unsigned short TargetIP[2];
310   unsigned char ProtocolType;
311
312   switch (ReadFrameBE_EMAC())                     // get frame type
313   {
314     case FRAME_ARP :                             // check for ARP
315     {
316       if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN)
317         if (ReadFrameBE_EMAC() == HARDW_ETH10)         // check for the right prot. etc.
318           if (ReadFrameBE_EMAC() == FRAME_IP)
319             if (ReadFrameBE_EMAC() == IP_HLEN_PLEN)
320               if (ReadFrameBE_EMAC() == OP_ARP_ANSWER)
321               {
322                 TCPStopTimer();                       // OK, now we've the MAC we wanted ;-)
323                 CopyFromFrame_EMAC(&RemoteMAC, 6);    // extract opponents MAC
324                 TCPFlags |= IP_ADDR_RESOLVED;
325               }
326       break;
327     }
328     case FRAME_IP :                                        // check for IP-type
329     {
330       if ((ReadFrameBE_EMAC() & 0xFF00 ) == IP_VER_IHL)     // IPv4, IHL=5 (20 Bytes Header)
331       {                                                    // ignore Type Of Service
332         RecdIPFrameLength = ReadFrameBE_EMAC();             // get IP frame's length
333         ReadFrameBE_EMAC();                                 // ignore identification
334
335         if (!(ReadFrameBE_EMAC() & (IP_FLAG_MOREFRAG | IP_FRAGOFS_MASK)))  // only unfragm. frames
336         {
337           ProtocolType = ReadFrameBE_EMAC() & 0xFF;         // get protocol, ignore TTL
338           ReadFrameBE_EMAC();                               // ignore checksum
339           CopyFromFrame_EMAC(&RecdFrameIP, 4);              // get source IP
340           CopyFromFrame_EMAC(&TargetIP, 4);                 // get destination IP
341
342           if (!memcmp(&MyIP, &TargetIP, 4))                // is it for us?
343             switch (ProtocolType) {
344               case PROT_ICMP : { ProcessICMPFrame(); break; }
345               case PROT_TCP  : { ProcessTCPFrame(); break; }
346               case PROT_UDP  : break;                      // not implemented!
347             }
348         }     
349       }
350       break;
351     }
352   }
353 }
354
355 // easyWEB internal function
356 // we've just rec'd an ICMP-frame (Internet Control Message Protocol)
357 // check what to do and branch to the appropriate sub-function
358
359 void ProcessICMPFrame(void)
360 {
361   unsigned short ICMPTypeAndCode;
362
363   ICMPTypeAndCode = ReadFrameBE_EMAC();           // get Message Type and Code
364   ReadFrameBE_EMAC();                             // ignore ICMP checksum
365
366   switch (ICMPTypeAndCode >> 8) {                // check type
367     case ICMP_ECHO :                             // is echo request?
368     {
369       PrepareICMP_ECHO_REPLY();                  // echo as much as we can...
370       break;
371     }
372   }
373 }
374
375 // easyWEB internal function
376 // we've just rec'd an TCP-frame (Transmission Control Protocol)
377 // this function mainly implements the TCP state machine according to RFC793
378
379 void ProcessTCPFrame(void)
380 {
381   unsigned short TCPSegSourcePort;               // segment's source port
382   unsigned short TCPSegDestPort;                 // segment's destination port
383   unsigned long TCPSegSeq;                       // segment's sequence number
384   unsigned long TCPSegAck;                       // segment's acknowledge number
385   unsigned short TCPCode;                        // TCP code and header length
386   unsigned char TCPHeaderSize;                   // real TCP header length
387   unsigned short NrOfDataBytes;                  // real number of data
388    
389   TCPSegSourcePort = ReadFrameBE_EMAC();                    // get ports
390   TCPSegDestPort = ReadFrameBE_EMAC();
391
392   if (TCPSegDestPort != TCPLocalPort) return;              // drop segment if port doesn't match
393
394   TCPSegSeq = (unsigned long)ReadFrameBE_EMAC() << 16;      // get segment sequence nr.
395   TCPSegSeq |= ReadFrameBE_EMAC();
396
397   TCPSegAck = (unsigned long)ReadFrameBE_EMAC() << 16;      // get segment acknowledge nr.
398   TCPSegAck |= ReadFrameBE_EMAC();
399
400   TCPCode = ReadFrameBE_EMAC();                             // get control bits, header length...
401
402   TCPHeaderSize = (TCPCode & DATA_OFS_MASK) >> 10;         // header length in bytes
403   NrOfDataBytes = RecdIPFrameLength - IP_HEADER_SIZE - TCPHeaderSize;     // seg. text length
404
405   if (NrOfDataBytes > MAX_TCP_RX_DATA_SIZE) return;        // packet too large for us :...-(
406
407   if (TCPHeaderSize > TCP_HEADER_SIZE)                     // ignore options if any
408     DummyReadFrame_EMAC(TCPHeaderSize - TCP_HEADER_SIZE);
409
410   switch (TCPStateMachine)                                 // implement the TCP state machine
411   {
412     case CLOSED :
413     {
414       if (!(TCPCode & TCP_CODE_RST))
415       {
416         TCPRemotePort = TCPSegSourcePort;
417         memcpy(&RemoteMAC, &RecdFrameMAC, 6);              // save opponents MAC and IP
418         memcpy(&RemoteIP, &RecdFrameIP, 4);                // for later use
419
420         if (TCPCode & TCP_CODE_ACK)                        // make the reset sequence
421         {                                                  // acceptable to the other
422           TCPSeqNr = TCPSegAck;                            // TCP
423           PrepareTCP_FRAME(TCP_CODE_RST);
424         }
425         else
426         {
427           TCPSeqNr = 0;
428           TCPAckNr = TCPSegSeq + NrOfDataBytes;
429           if (TCPCode & (TCP_CODE_SYN | TCP_CODE_FIN)) TCPAckNr++;
430           PrepareTCP_FRAME(TCP_CODE_RST | TCP_CODE_ACK);
431         }
432       }
433       break;
434     } 
435     case LISTENING :
436     {
437       if (!(TCPCode & TCP_CODE_RST))                       // ignore segment containing RST
438       {
439         TCPRemotePort = TCPSegSourcePort;
440         memcpy(&RemoteMAC, &RecdFrameMAC, 6);              // save opponents MAC and IP
441         memcpy(&RemoteIP, &RecdFrameIP, 4);                // for later use
442
443         if (TCPCode & TCP_CODE_ACK)                        // reset a bad
444         {                                                  // acknowledgement
445           TCPSeqNr = TCPSegAck;
446           PrepareTCP_FRAME(TCP_CODE_RST);
447         }
448         else if (TCPCode & TCP_CODE_SYN)
449         {
450           TCPAckNr = TCPSegSeq + 1;                           // get remote ISN, next byte we expect
451             TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (T0TC & 0xFFFF);  // Keil: changed from TAR to T0TC;
452                                                               // set local ISN
453           TCPUNASeqNr = TCPSeqNr + 1;                         // one byte out -> increase by one
454           PrepareTCP_FRAME(TCP_CODE_SYN | TCP_CODE_ACK);
455           LastFrameSent = TCP_SYN_ACK_FRAME;
456           TCPStartRetryTimer();
457           TCPStateMachine = SYN_RECD;
458         }
459       }
460       break;
461     }
462     case SYN_SENT :
463     {
464       if (memcmp(&RemoteIP, &RecdFrameIP, 4)) break;  // drop segment if its IP doesn't belong
465                                                       // to current session
466
467       if (TCPSegSourcePort != TCPRemotePort) break;   // drop segment if port doesn't match
468      
469       if (TCPCode & TCP_CODE_ACK)                // ACK field significant?
470         if (TCPSegAck != TCPUNASeqNr)            // is our ISN ACKed?
471         {
472           if (!(TCPCode & TCP_CODE_RST))
473           {
474             TCPSeqNr = TCPSegAck;
475             PrepareTCP_FRAME(TCP_CODE_RST);
476           }
477           break;                                 // drop segment
478         }
479
480       if (TCPCode & TCP_CODE_RST)                // RST??
481       {
482         if (TCPCode & TCP_CODE_ACK)              // if ACK was acceptable, reset
483         {                                        // connection
484           TCPStateMachine = CLOSED;
485           TCPFlags = 0;                          // reset all flags, stop retransmission...
486           SocketStatus = SOCK_ERR_CONN_RESET;
487         }
488         break;                                   // drop segment
489       }
490        
491       if (TCPCode & TCP_CODE_SYN)                // SYN??
492       {
493         TCPAckNr = TCPSegSeq;                    // get opponents ISN
494         TCPAckNr++;                              // inc. by one...
495
496         if (TCPCode & TCP_CODE_ACK)
497         {
498           TCPStopTimer();                        // stop retransmission, other TCP got our SYN
499           TCPSeqNr = TCPUNASeqNr;                // advance our sequence number
500
501           PrepareTCP_FRAME(TCP_CODE_ACK);        // ACK this ISN
502           TCPStateMachine = ESTABLISHED;
503           SocketStatus |= SOCK_CONNECTED;
504           SocketStatus |= SOCK_TX_BUF_RELEASED;  // user may send data now :-)
505         }
506         else
507         {
508           TCPStopTimer();
509           PrepareTCP_FRAME(TCP_CODE_SYN | TCP_CODE_ACK);   // our SYN isn't ACKed yet,
510           LastFrameSent = TCP_SYN_ACK_FRAME;               // now continue with sending
511           TCPStartRetryTimer();                            // SYN_ACK frames
512           TCPStateMachine = SYN_RECD;
513         }
514       }
515       break;
516     }
517     default :
518     {
519       if (memcmp(&RemoteIP, &RecdFrameIP, 4)) break;  // drop segment if IP doesn't belong
520                                                       // to current session
521
522       if (TCPSegSourcePort != TCPRemotePort) break;   // drop segment if port doesn't match
523
524       if (TCPSegSeq != TCPAckNr) break;               // drop if it's not the segment we expect
525            
526       if (TCPCode & TCP_CODE_RST)                // RST??
527       {
528         TCPStateMachine = CLOSED;                // close the state machine
529         TCPFlags = 0;                            // reset all flags, stop retransmission...
530         SocketStatus = SOCK_ERR_CONN_RESET;      // indicate an error to user
531         break;
532       }
533
534       if (TCPCode & TCP_CODE_SYN)                // SYN??
535       {
536         PrepareTCP_FRAME(TCP_CODE_RST);          // is NOT allowed here! send a reset,
537         TCPStateMachine = CLOSED;                // close connection...
538         TCPFlags = 0;                            // reset all flags, stop retransmission...
539         SocketStatus = SOCK_ERR_REMOTE;          // fatal error!
540         break;                                   // ...and drop the frame
541       }
542
543       if (!(TCPCode & TCP_CODE_ACK)) break;      // drop segment if the ACK bit is off
544
545       if (TCPSegAck == TCPUNASeqNr)              // is our last data sent ACKed?
546       {
547         TCPStopTimer();                          // stop retransmission
548         TCPSeqNr = TCPUNASeqNr;                  // advance our sequence number
549
550         switch (TCPStateMachine)                 // change state if necessary
551         {
552           case SYN_RECD :                        // ACK of our SYN?
553           {
554             TCPStateMachine = ESTABLISHED;       // user may send data now :-)
555             SocketStatus |= SOCK_CONNECTED;
556             break;
557           }
558           case FIN_WAIT_1 : { TCPStateMachine = FIN_WAIT_2; break; } // ACK of our FIN?
559           case CLOSING :    { TCPStateMachine = TIME_WAIT; break; }  // ACK of our FIN?
560           case LAST_ACK :                                            // ACK of our FIN?
561           {
562             TCPStateMachine = CLOSED;
563             TCPFlags = 0;                        // reset all flags, stop retransmission...
564             SocketStatus &= SOCK_DATA_AVAILABLE; // clear all flags but data available
565             break;
566           }
567           case TIME_WAIT :
568           {
569             PrepareTCP_FRAME(TCP_CODE_ACK);      // ACK a retransmission of remote FIN
570             TCPRestartTimer();                   // restart TIME_WAIT timeout
571             break;
572           }
573         }
574        
575         if (TCPStateMachine == ESTABLISHED)      // if true, give the frame buffer back
576           SocketStatus |= SOCK_TX_BUF_RELEASED;  // to user
577       }
578
579       if ((TCPStateMachine == ESTABLISHED) || (TCPStateMachine == FIN_WAIT_1) || (TCPStateMachine == FIN_WAIT_2))
580         if (NrOfDataBytes)                                 // data available?
581           if (!(SocketStatus & SOCK_DATA_AVAILABLE))       // rx data-buffer empty?
582           {
583             DummyReadFrame_EMAC(6);                        // ignore window, checksum, urgent pointer
584             CopyFromFrame_EMAC(RxTCPBuffer, NrOfDataBytes);// fetch data and
585             TCPRxDataCount = NrOfDataBytes;                // ...tell the user...
586             SocketStatus |= SOCK_DATA_AVAILABLE;           // indicate the new data to user
587             TCPAckNr += NrOfDataBytes;
588             PrepareTCP_FRAME(TCP_CODE_ACK);                // ACK rec'd data
589           }
590              
591       if (TCPCode & TCP_CODE_FIN)                // FIN??
592       {
593         switch (TCPStateMachine)
594         {
595           case SYN_RECD :
596           case ESTABLISHED :
597           {
598             TCPStateMachine = CLOSE_WAIT;
599             break;
600           }
601           case FIN_WAIT_1 :
602           {                                      // if our FIN was ACKed, we automatically
603             TCPStateMachine = CLOSING;           // enter FIN_WAIT_2 (look above) and therefore
604             SocketStatus &= ~SOCK_CONNECTED;     // TIME_WAIT
605             break;
606           }
607           case FIN_WAIT_2 :
608           {
609             TCPStartTimeWaitTimer();
610             TCPStateMachine = TIME_WAIT;
611             SocketStatus &= ~SOCK_CONNECTED;           
612             break;
613           }
614           case TIME_WAIT :
615           {
616             TCPRestartTimer();
617             break;
618           }
619         }
620         TCPAckNr++;                              // ACK remote's FIN flag
621         PrepareTCP_FRAME(TCP_CODE_ACK);
622       }
623     }
624   }
625 }
626
627 // easyWEB internal function
628 // prepares the TxFrame2-buffer to send an ARP-request
629
630 void PrepareARP_REQUEST(void)
631 {
632   // Ethernet
633   memset(&TxFrame2[ETH_DA_OFS], (char)0xFF, 6);                  // we don't know opposites MAC!
634   memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
635   *(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);
636
637   // ARP
638   *(unsigned short *)&TxFrame2[ARP_HARDW_OFS] = SWAPB(HARDW_ETH10);
639   *(unsigned short *)&TxFrame2[ARP_PROT_OFS] = SWAPB(FRAME_IP);
640   *(unsigned short *)&TxFrame2[ARP_HLEN_PLEN_OFS] = SWAPB(IP_HLEN_PLEN);
641   *(unsigned short *)&TxFrame2[ARP_OPCODE_OFS] = SWAPB(OP_ARP_REQUEST);
642   memcpy(&TxFrame2[ARP_SENDER_HA_OFS], &MyMAC, 6);
643   memcpy(&TxFrame2[ARP_SENDER_IP_OFS], &MyIP, 4);
644   memset(&TxFrame2[ARP_TARGET_HA_OFS], 0x00, 6);           // we don't know opposites MAC!
645
646   if (((RemoteIP[0] ^ MyIP[0]) & SubnetMask[0]) || ((RemoteIP[1] ^ MyIP[1]) & SubnetMask[1]))
647     memcpy(&TxFrame2[ARP_TARGET_IP_OFS], &GatewayIP, 4);   // IP not in subnet, use gateway
648   else
649     memcpy(&TxFrame2[ARP_TARGET_IP_OFS], &RemoteIP, 4);    // other IP is next to us...
650
651   TxFrame2Size = ETH_HEADER_SIZE + ARP_FRAME_SIZE;
652   TransmitControl |= SEND_FRAME2;
653 }
654
655 // easyWEB internal function
656 // prepares the TxFrame2-buffer to send an ARP-answer (reply)
657
658 void PrepareARP_ANSWER(void)
659 {
660   // Ethernet
661   memcpy(&TxFrame2[ETH_DA_OFS], &RecdFrameMAC, 6);
662   memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
663   *(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);
664
665   // ARP
666   *(unsigned short *)&TxFrame2[ARP_HARDW_OFS] = SWAPB(HARDW_ETH10);
667   *(unsigned short *)&TxFrame2[ARP_PROT_OFS] = SWAPB(FRAME_IP);
668   *(unsigned short *)&TxFrame2[ARP_HLEN_PLEN_OFS] = SWAPB(IP_HLEN_PLEN);
669   *(unsigned short *)&TxFrame2[ARP_OPCODE_OFS] = SWAPB(OP_ARP_ANSWER);
670   memcpy(&TxFrame2[ARP_SENDER_HA_OFS], &MyMAC, 6);
671   memcpy(&TxFrame2[ARP_SENDER_IP_OFS], &MyIP, 4);
672   memcpy(&TxFrame2[ARP_TARGET_HA_OFS], &RecdFrameMAC, 6);
673   memcpy(&TxFrame2[ARP_TARGET_IP_OFS], &RecdFrameIP, 4);
674
675   TxFrame2Size = ETH_HEADER_SIZE + ARP_FRAME_SIZE;
676   TransmitControl |= SEND_FRAME2;
677 }
678
679 // easyWEB internal function
680 // prepares the TxFrame2-buffer to send an ICMP-echo-reply
681
682 void PrepareICMP_ECHO_REPLY(void)
683 {
684   unsigned short ICMPDataCount;
685
686   if (RecdIPFrameLength > MAX_ETH_TX_DATA_SIZE)                      // don't overload TX-buffer
687     ICMPDataCount = MAX_ETH_TX_DATA_SIZE - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
688   else
689     ICMPDataCount = RecdIPFrameLength - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
690
691   // Ethernet
692   memcpy(&TxFrame2[ETH_DA_OFS], &RecdFrameMAC, 6);
693   memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
694   *(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
695  
696   // IP   
697   *(unsigned short *)&TxFrame2[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL);
698   WriteWBE(&TxFrame2[IP_TOTAL_LENGTH_OFS], IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMPDataCount);
699   *(unsigned short *)&TxFrame2[IP_IDENT_OFS] = 0;
700   *(unsigned short *)&TxFrame2[IP_FLAGS_FRAG_OFS] = 0;
701   *(unsigned short *)&TxFrame2[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_ICMP);
702   *(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = 0;
703   memcpy(&TxFrame2[IP_SOURCE_OFS], &MyIP, 4);
704   memcpy(&TxFrame2[IP_DESTINATION_OFS], &RecdFrameIP, 4);
705   *(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
706
707   // ICMP
708   *(unsigned short *)&TxFrame2[ICMP_TYPE_CODE_OFS] = SWAPB(ICMP_ECHO_REPLY << 8);
709   *(unsigned short *)&TxFrame2[ICMP_CHKSUM_OFS] = 0;                   // initialize checksum field
710
711   CopyFromFrame_EMAC(&TxFrame2[ICMP_DATA_OFS], ICMPDataCount);        // get data to echo...
712   *(unsigned short *)&TxFrame2[ICMP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_DATA_OFS], ICMPDataCount + ICMP_HEADER_SIZE, 0);
713
714   TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMPDataCount;
715   TransmitControl |= SEND_FRAME2;
716 }
717
718 // easyWEB internal function
719 // prepares the TxFrame2-buffer to send a general TCP frame
720 // the TCPCode-field is passed as an argument
721
722 void PrepareTCP_FRAME(unsigned short TCPCode)
723 {
724   // Ethernet
725   memcpy(&TxFrame2[ETH_DA_OFS], &RemoteMAC, 6);
726   memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
727   *(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
728  
729   // IP   
730   *(unsigned short *)&TxFrame2[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL | IP_TOS_D);
731
732   if (TCPCode & TCP_CODE_SYN)                    // if SYN, we want to use the MSS option
733     *(unsigned short *)&TxFrame2[IP_TOTAL_LENGTH_OFS] = SWAPB(IP_HEADER_SIZE + TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE);
734   else
735     *(unsigned short *)&TxFrame2[IP_TOTAL_LENGTH_OFS] = SWAPB(IP_HEADER_SIZE + TCP_HEADER_SIZE);
736    
737   *(unsigned short *)&TxFrame2[IP_IDENT_OFS] = 0;
738   *(unsigned short *)&TxFrame2[IP_FLAGS_FRAG_OFS] = 0;
739   *(unsigned short *)&TxFrame2[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_TCP);
740   *(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = 0;
741   memcpy(&TxFrame2[IP_SOURCE_OFS], &MyIP, 4);
742   memcpy(&TxFrame2[IP_DESTINATION_OFS], &RemoteIP, 4);
743   *(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
744
745   // TCP
746   WriteWBE(&TxFrame2[TCP_SRCPORT_OFS], TCPLocalPort);
747   WriteWBE(&TxFrame2[TCP_DESTPORT_OFS], TCPRemotePort);
748
749   WriteDWBE(&TxFrame2[TCP_SEQNR_OFS], TCPSeqNr);
750   WriteDWBE(&TxFrame2[TCP_ACKNR_OFS], TCPAckNr);
751
752   *(unsigned short *)&TxFrame2[TCP_WINDOW_OFS] = SWAPB(MAX_TCP_RX_DATA_SIZE);    // data bytes to accept
753   *(unsigned short *)&TxFrame2[TCP_CHKSUM_OFS] = 0;             // initalize checksum
754   *(unsigned short *)&TxFrame2[TCP_URGENT_OFS] = 0;
755
756   if (TCPCode & TCP_CODE_SYN)                    // if SYN, we want to use the MSS option
757   {
758     *(unsigned short *)&TxFrame2[TCP_DATA_CODE_OFS] = SWAPB(0x6000 | TCPCode);   // TCP header length = 24
759     *(unsigned short *)&TxFrame2[TCP_DATA_OFS] = SWAPB(TCP_OPT_MSS);             // MSS option
760     *(unsigned short *)&TxFrame2[TCP_DATA_OFS + 2] = SWAPB(MAX_TCP_RX_DATA_SIZE);// max. length of TCP-data we accept
761     *(unsigned short *)&TxFrame2[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[TCP_SRCPORT_OFS], TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE, 1);
762     TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE;
763   }
764   else
765   {
766     *(unsigned short *)&TxFrame2[TCP_DATA_CODE_OFS] = SWAPB(0x5000 | TCPCode);   // TCP header length = 20
767     *(unsigned short *)&TxFrame2[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[TCP_SRCPORT_OFS], TCP_HEADER_SIZE, 1);
768     TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE;
769   }
770
771   TransmitControl |= SEND_FRAME2;
772 }
773
774 // easyWEB internal function
775 // prepares the TxFrame1-buffer to send a payload-packet
776
777 void PrepareTCP_DATA_FRAME(void)
778 {
779   // Ethernet
780   memcpy(&TxFrame1[ETH_DA_OFS], &RemoteMAC, 6);
781   memcpy(&TxFrame1[ETH_SA_OFS], &MyMAC, 6);
782   *(unsigned short *)&TxFrame1[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
783  
784   // IP   
785   *(unsigned short *)&TxFrame1[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL | IP_TOS_D);
786   WriteWBE(&TxFrame1[IP_TOTAL_LENGTH_OFS], IP_HEADER_SIZE + TCP_HEADER_SIZE + TCPTxDataCount);
787   *(unsigned short *)&TxFrame1[IP_IDENT_OFS] = 0;
788   *(unsigned short *)&TxFrame1[IP_FLAGS_FRAG_OFS] = 0;
789   *(unsigned short *)&TxFrame1[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_TCP);
790   *(unsigned short *)&TxFrame1[IP_HEAD_CHKSUM_OFS] = 0;
791   memcpy(&TxFrame1[IP_SOURCE_OFS], &MyIP, 4);
792   memcpy(&TxFrame1[IP_DESTINATION_OFS], &RemoteIP, 4);
793   *(unsigned short *)&TxFrame1[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame1[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
794
795   // TCP
796   WriteWBE(&TxFrame1[TCP_SRCPORT_OFS], TCPLocalPort);
797   WriteWBE(&TxFrame1[TCP_DESTPORT_OFS], TCPRemotePort);
798
799   WriteDWBE(&TxFrame1[TCP_SEQNR_OFS], TCPSeqNr);
800   WriteDWBE(&TxFrame1[TCP_ACKNR_OFS], TCPAckNr);
801   *(unsigned short *)&TxFrame1[TCP_DATA_CODE_OFS] = SWAPB(0x5000 | TCP_CODE_ACK);   // TCP header length = 20
802   *(unsigned short *)&TxFrame1[TCP_WINDOW_OFS] = SWAPB(MAX_TCP_RX_DATA_SIZE);       // data bytes to accept
803   *(unsigned short *)&TxFrame1[TCP_CHKSUM_OFS] = 0;
804   *(unsigned short *)&TxFrame1[TCP_URGENT_OFS] = 0;
805   *(unsigned short *)&TxFrame1[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame1[TCP_SRCPORT_OFS], TCP_HEADER_SIZE + TCPTxDataCount, 1);
806 }
807
808 // easyWEB internal function
809 // calculates the TCP/IP checksum. if 'IsTCP != 0', the TCP pseudo-header
810 // will be included.
811
812 unsigned short CalcChecksum(void *Start, unsigned short Count, unsigned char IsTCP)
813 {
814   unsigned long Sum = 0;
815   unsigned short * piStart;                        // Keil: Pointer added to correct expression
816
817   if (IsTCP) {                                   // if we've a TCP frame...
818     Sum += MyIP[0];                              // ...include TCP pseudo-header
819     Sum += MyIP[1];
820     Sum += RemoteIP[0];
821     Sum += RemoteIP[1];
822     Sum += SwapBytes(Count);                     // TCP header length plus data length
823     Sum += SWAPB(PROT_TCP);
824   }
825
826   piStart = Start;                               // Keil: Line added
827   while (Count > 1) {                            // sum words
828 //  Sum += *((unsigned short *)Start)++;                     // Keil: Line replaced with following line
829     Sum += *piStart++;
830     Count -= 2;
831   }
832
833   if (Count)                                     // add left-over byte, if any
834 //  Sum += *(unsigned char *)Start;              // Keil: Line replaced with following line
835     Sum += *(unsigned char *)piStart;
836  
837   while (Sum >> 16)                              // fold 32-bit sum to 16 bits
838     Sum = (Sum & 0xFFFF) + (Sum >> 16);
839  
840   return ~Sum;
841 }
842
843 // easyWEB internal function
844 // starts the timer as a retry-timer (used for retransmission-timeout)
845
846 void TCPStartRetryTimer(void)
847 {
848   TCPTimer = 0;
849   RetryCounter = MAX_RETRYS;
850   TCPFlags |= TCP_TIMER_RUNNING;
851   TCPFlags |= TIMER_TYPE_RETRY;
852 }
853
854 // easyWEB internal function
855 // starts the timer as a 'TIME_WAIT'-timer (used to finish a TCP-session)
856
857 void TCPStartTimeWaitTimer(void)
858 {
859   TCPTimer = 0;
860   TCPFlags |= TCP_TIMER_RUNNING;
861   TCPFlags &= ~TIMER_TYPE_RETRY; 
862 }
863
864 // easyWEB internal function
865 // restarts the timer
866
867 void TCPRestartTimer(void)
868 {
869   TCPTimer = 0;
870 }
871
872 // easyWEB internal function
873 // stopps the timer
874
875 void TCPStopTimer(void)
876 {
877   TCPFlags &= ~TCP_TIMER_RUNNING;
878 }
879
880 // easyWEB internal function
881 // if a retransmission-timeout occured, check which packet
882 // to resend.
883
884 void TCPHandleRetransmission(void)
885 {
886   switch (LastFrameSent)
887   {
888     case ARP_REQUEST :       { PrepareARP_REQUEST(); break; }
889     case TCP_SYN_FRAME :     { PrepareTCP_FRAME(TCP_CODE_SYN); break; }
890     case TCP_SYN_ACK_FRAME : { PrepareTCP_FRAME(TCP_CODE_SYN | TCP_CODE_ACK); break; }
891     case TCP_FIN_FRAME :     { PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK); break; }
892     case TCP_DATA_FRAME :    { TransmitControl |= SEND_FRAME1; break; }
893   }
894 }
895
896 // easyWEB internal function
897 // if all retransmissions failed, close connection and indicate an error
898
899 void TCPHandleTimeout(void)
900 {
901   TCPStateMachine = CLOSED;
902
903   if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN)
904     SocketStatus = SOCK_ERR_ARP_TIMEOUT;         // indicate an error to user
905   else
906     SocketStatus = SOCK_ERR_TCP_TIMEOUT;
907
908   TCPFlags = 0;                                  // clear all flags
909 }
910
911
912 // easyWEB internal function
913 // function executed every 0.210s by the CPU. used for the
914 // inital sequence number generator (ISN) and the TCP-timer
915 void TCPClockHandler(void) __irq                // Keil: interrupt service routine for timer 0
916 {
917   ISNGenHigh++;                                  // upper 16 bits of initial sequence number
918   TCPTimer++;                                    // timer for retransmissions
919   T0IR        = 1;                               // Clear interrupt flag
920   VICVectAddr = 0;                               // Acknowledge Interrupt
921 }
922
923 // easyWEB internal function
924 // transfers the contents of 'TxFrame1'-Buffer to the EMAC
925
926 void SendFrame1(void)
927 {
928   CopyToFrame_EMAC(TxFrame1, TxFrame1Size);
929 }
930
931 // easyWEB internal function
932 // transfers the contents of 'TxFrame2'-Buffer to the EMAC
933
934 void SendFrame2(void)
935 {
936   CopyToFrame_EMAC(TxFrame2, TxFrame2Size);
937 }
938
939 // easyWEB internal function
940 // help function to write a WORD in big-endian byte-order
941 // to MCU-memory
942
943 void WriteWBE(unsigned char *Add, unsigned short Data)
944 {
945   *Add++ = Data >> 8;
946   *Add = (char)Data;
947 }
948
949 // easyWEB internal function
950 // help function to write a DWORD in big-endian byte-order
951 // to MCU-memory
952
953 void WriteDWBE(unsigned char *Add, unsigned long Data)
954 {
955   *Add++ = Data >> 24;
956   *Add++ = Data >> 16;
957   *Add++ = Data >> 8;
958   *Add = (char)Data;
959 }
960
961 // easyWEB internal function
962 // help function to swap the byte order of a WORD
963
964 unsigned short SwapBytes(unsigned short Data)
965 {
966   return (Data >> 8) | (Data << 8);
967 }
968
Note: See TracBrowser for help on using the browser.