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