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 |
|
---|