root/webserver/example/EasyWEB/tcpip.c

Revision 12, 35.7 kB (checked in by phil, 15 years ago)

Added Interrupt Enable Commamnd. RAM Debug, Flash Release working (still needs reset after power-on)

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