]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Sockets/TftpServer/TftpServer.c
AppPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / AppPkg / Applications / Sockets / TftpServer / TftpServer.c
CommitLineData
7dc13291 1/** @file\r
2 This is a simple TFTP server application\r
3\r
bcb96695
MK
4 Copyright (c) 2011, 2012, Intel Corporation. All rights reserved.\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
f6e5cdd5 6\r
7dc13291 7**/\r
8\r
9#include <TftpServer.h>\r
10\r
f6e5cdd5 11TSDT_TFTP_SERVER mTftpServer; ///< TFTP server's control structure\r
12volatile BOOLEAN mbTftpServerExit; ///< Set TRUE to cause TFTP server to exit\r
7dc13291 13\r
14\r
15/**\r
f6e5cdd5 16 Read file data into a buffer\r
7dc13291 17\r
f6e5cdd5 18 @param [in] pContext Connection context structure address\r
7dc13291 19\r
f6e5cdd5 20 @retval TRUE if a read error occurred\r
7dc13291 21\r
22**/\r
f6e5cdd5 23BOOLEAN\r
24BufferFill (\r
25 IN TSDT_CONNECTION_CONTEXT * pContext\r
7dc13291 26 )\r
27{\r
f6e5cdd5 28 BOOLEAN bReadError;\r
29 size_t BytesRead;\r
30 UINT64 LengthInBytes;\r
7dc13291 31\r
32 DBG_ENTER ( );\r
33\r
34 //\r
f6e5cdd5 35 // Use break instead of goto\r
7dc13291 36 //\r
f6e5cdd5 37 bReadError = FALSE;\r
7dc13291 38 for ( ; ; ) {\r
39 //\r
f6e5cdd5 40 // Determine if there is any work to do\r
41 //\r
42 LengthInBytes = DIM ( pContext->FileData ) >> 1;\r
43 if (( pContext->ValidBytes > LengthInBytes )\r
44 || ( 0 == pContext->BytesRemaining )) {\r
45 break;\r
46 }\r
47\r
48 //\r
49 // Determine the number of bytes to read\r
50 //\r
51 if ( LengthInBytes > pContext->BytesRemaining ) {\r
52 LengthInBytes = pContext->BytesRemaining;\r
53 }\r
54\r
55 //\r
56 // Read in the next portion of the file\r
57 //\r
58 BytesRead = fread ( pContext->pFill,\r
59 1,\r
60 (size_t)LengthInBytes,\r
61 pContext->File );\r
62 if ( -1 == BytesRead ) {\r
63 bReadError = TRUE;\r
7dc13291 64 break;\r
65 }\r
66\r
f6e5cdd5 67 //\r
68 // Account for the file data read\r
69 //\r
70 pContext->BytesRemaining -= BytesRead;\r
71 pContext->ValidBytes += BytesRead;\r
72 DEBUG (( DEBUG_FILE_BUFFER,\r
73 "0x%08x: Buffer filled with %Ld bytes, %Ld bytes ramaining\r\n",\r
74 pContext->pFill,\r
75 BytesRead,\r
76 pContext->BytesRemaining ));\r
77\r
78 //\r
79 // Set the next buffer location\r
80 //\r
81 pContext->pFill += BytesRead;\r
82 if ( pContext->pEnd <= pContext->pFill ) {\r
83 pContext->pFill = &pContext->FileData[ 0 ];\r
84 }\r
85\r
86 //\r
87 // Verify that the end of the buffer is reached\r
88 //\r
89 ASSERT ( 0 == ( DIM ( pContext->FileData ) & 1 ));\r
90 break;\r
91 }\r
92\r
93 //\r
94 // Return the read status\r
95 //\r
96 DBG_EXIT ( );\r
97 return bReadError;\r
98}\r
99\r
100\r
101/**\r
102 Add a connection context to the list of connection contexts.\r
103\r
104 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
105 @param [in] SocketFd Socket file descriptor\r
106\r
107 @retval Context structure address, NULL if allocation fails\r
108\r
109**/\r
110TSDT_CONNECTION_CONTEXT *\r
111ContextAdd (\r
112 IN TSDT_TFTP_SERVER * pTftpServer,\r
113 IN int SocketFd\r
114 )\r
115{\r
116 TSDT_CONNECTION_CONTEXT * pContext;\r
117 TFTP_PACKET * pEnd;\r
118 TFTP_PACKET * pPacket;\r
119\r
120 DBG_ENTER ( );\r
121\r
122 //\r
123 // Allocate a new context\r
124 //\r
125 pContext = (TSDT_CONNECTION_CONTEXT *)AllocateZeroPool ( sizeof ( *pContext ));\r
126 if ( NULL != pContext ) {\r
7dc13291 127 //\r
128 // Initialize the context\r
129 //\r
f6e5cdd5 130 pContext->SocketFd = SocketFd;\r
7dc13291 131 CopyMem ( &pContext->RemoteAddress,\r
132 &pTftpServer->RemoteAddress,\r
133 sizeof ( pContext->RemoteAddress ));\r
f6e5cdd5 134 pContext->BlockSize = 512;\r
135\r
136 //\r
137 // Buffer management\r
138 //\r
139 pContext->pFill = &pContext->FileData[ 0 ];\r
140 pContext->pEnd = &pContext->FileData[ sizeof ( pContext->FileData )];\r
141 pContext->pBuffer = pContext->pFill;\r
142\r
143 //\r
144 // Window management\r
145 //\r
146 pContext->MaxTimeout = MultU64x32 ( PcdGet32 ( Tftp_MaxTimeoutInSec ),\r
147 2 * 1000 * 1000 * 1000 );\r
148 pContext->Rtt2x = pContext->MaxTimeout;\r
149 pContext->WindowSize = MAX_PACKETS;\r
150 WindowTimeout ( pContext );\r
151\r
152 //\r
153 // Place the packets on the free list\r
154 //\r
155 pPacket = &pContext->Tx[ 0 ];\r
156 pEnd = &pPacket[ DIM ( pContext->Tx )];\r
157 while ( pEnd > pPacket ) {\r
158 PacketFree ( pContext, pPacket );\r
159 pPacket += 1;\r
160 }\r
7dc13291 161\r
162 //\r
163 // Display the new context\r
164 //\r
f6e5cdd5 165 if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
166 DEBUG (( DEBUG_PORT_WORK,\r
167 "0x%08x: Context for %d.%d.%d.%d:%d\r\n",\r
168 pContext,\r
169 (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
170 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
171 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
172 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
173 htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
174 }\r
175 else {\r
176 DEBUG (( DEBUG_PORT_WORK,\r
177 "0x%08x: Context for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
178 pContext,\r
179 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
180 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
181 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
182 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
183 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
184 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
185 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
186 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
187 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
188 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
189 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
190 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
191 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
192 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
193 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
194 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
195 htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
196 }\r
7dc13291 197\r
198 //\r
199 // Add the context to the context list\r
200 //\r
201 pContext->pNext = pTftpServer->pContextList;\r
202 pTftpServer->pContextList = pContext;\r
7dc13291 203 }\r
204\r
205 //\r
206 // Return the connection context\r
207 //\r
208 DBG_EXIT_STATUS ( pContext );\r
209 return pContext;\r
210}\r
211\r
212\r
213/**\r
214 Locate a remote connection context.\r
215\r
f6e5cdd5 216 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
7dc13291 217 @param [in] pIpAddress The start of the remote IP address in network order\r
7dc13291 218 @param [in] Port The remote port number\r
219\r
220 @retval Context structure address, NULL if not found\r
221\r
222**/\r
223TSDT_CONNECTION_CONTEXT *\r
224ContextFind (\r
225 IN TSDT_TFTP_SERVER * pTftpServer\r
226 )\r
227{\r
228 TSDT_CONNECTION_CONTEXT * pContext;\r
229\r
230 DBG_ENTER ( );\r
231\r
232 //\r
233 // Walk the list of connection contexts\r
234 //\r
235 pContext = pTftpServer->pContextList;\r
236 while ( NULL != pContext ) {\r
237 //\r
238 // Attempt to locate the remote network connection\r
239 //\r
f6e5cdd5 240 if ( 0 == memcmp ( &pTftpServer->RemoteAddress,\r
241 &pContext->RemoteAddress,\r
242 pTftpServer->RemoteAddress.v6.sin6_len )) {\r
7dc13291 243 //\r
244 // The connection was found\r
245 //\r
246 DEBUG (( DEBUG_TFTP_REQUEST,\r
247 "0x%08x: pContext found\r\n",\r
248 pContext ));\r
249 break;\r
250 }\r
251\r
252 //\r
253 // Set the next context\r
254 //\r
255 pContext = pContext->pNext;\r
256 }\r
257\r
258 //\r
259 // Return the connection context structure address\r
260 //\r
261 DBG_EXIT_HEX ( pContext );\r
262 return pContext;\r
263}\r
264\r
265\r
266/**\r
267 Remove a context from the list.\r
268\r
f6e5cdd5 269 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
270 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
7dc13291 271\r
272**/\r
273VOID\r
274ContextRemove (\r
275 IN TSDT_TFTP_SERVER * pTftpServer,\r
276 IN TSDT_CONNECTION_CONTEXT * pContext\r
277 )\r
278{\r
279 TSDT_CONNECTION_CONTEXT * pNextContext;\r
280 TSDT_CONNECTION_CONTEXT * pPreviousContext;\r
281\r
282 DBG_ENTER ( );\r
283\r
284 //\r
285 // Attempt to locate the context in the list\r
286 //\r
287 pPreviousContext = NULL;\r
288 pNextContext = pTftpServer->pContextList;\r
289 while ( NULL != pNextContext ) {\r
290 //\r
291 // Determine if the context was found\r
292 //\r
293 if ( pNextContext == pContext ) {\r
294 //\r
295 // Remove the context from the list\r
296 //\r
297 if ( NULL == pPreviousContext ) {\r
298 pTftpServer->pContextList = pContext->pNext;\r
299 }\r
300 else {\r
301 pPreviousContext->pNext = pContext->pNext;\r
302 }\r
303 break;\r
304 }\r
305\r
306 //\r
307 // Set the next context\r
308 //\r
309 pPreviousContext = pNextContext;\r
310 pNextContext = pNextContext->pNext;\r
311 }\r
312\r
313 //\r
314 // Determine if the context was found\r
315 //\r
316 if ( NULL != pContext ) {\r
317 //\r
318 // Return the resources\r
319 //\r
320 gBS->FreePool ( pContext );\r
321 }\r
322\r
323 DBG_EXIT ( );\r
324}\r
325\r
326\r
327/**\r
f6e5cdd5 328 Queue data packets for transmission\r
329\r
330 @param [in] pContext Connection context structure address\r
7dc13291 331\r
f6e5cdd5 332 @retval TRUE if a read error occurred\r
7dc13291 333\r
334**/\r
f6e5cdd5 335BOOLEAN\r
336PacketFill (\r
337 IN TSDT_CONNECTION_CONTEXT * pContext\r
7dc13291 338 )\r
339{\r
f6e5cdd5 340 BOOLEAN bReadError;\r
341 UINT64 LengthInBytes;\r
342 UINT8 * pBuffer;\r
343 TFTP_PACKET * pPacket;\r
7dc13291 344\r
345 DBG_ENTER ( );\r
346\r
347 //\r
f6e5cdd5 348 // Use break instead of goto\r
7dc13291 349 //\r
f6e5cdd5 350 bReadError = FALSE;\r
351 for ( ; ; ) {\r
7dc13291 352 //\r
f6e5cdd5 353 // Fill the buffer if necessary\r
7dc13291 354 //\r
f6e5cdd5 355 bReadError = BufferFill ( pContext );\r
356 if ( bReadError ) {\r
7dc13291 357 //\r
f6e5cdd5 358 // File access mode not supported\r
7dc13291 359 //\r
f6e5cdd5 360 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r
361 "ERROR - File read failure!\r\n" ));\r
7dc13291 362\r
363 //\r
f6e5cdd5 364 // Tell the client of the error\r
7dc13291 365 //\r
f6e5cdd5 366 SendError ( pContext,\r
367 TFTP_ERROR_SEE_MSG,\r
368 (UINT8 *)"Read failure" );\r
369 break;\r
7dc13291 370 }\r
f6e5cdd5 371\r
372 //\r
373 // Determine if any packets can be filled\r
374 //\r
375 if ( pContext->bEofSent\r
376 || ( NULL == pContext->pFreeList )) {\r
7dc13291 377 //\r
f6e5cdd5 378 // All of the packets are filled\r
7dc13291 379 //\r
f6e5cdd5 380 break;\r
7dc13291 381 }\r
7dc13291 382\r
7dc13291 383 //\r
f6e5cdd5 384 // Set the TFTP opcode and block number\r
385 //\r
386 pPacket = PacketGet ( pContext );\r
387 pBuffer = &pPacket->TxBuffer[ 0 ];\r
388 *pBuffer++ = 0;\r
389 *pBuffer++ = TFTP_OP_DATA;\r
390 *pBuffer++ = (UINT8)( pContext->BlockNumber >> 8 );\r
391 *pBuffer++ = (UINT8)pContext->BlockNumber;\r
392\r
393 //\r
394 // Determine how much data needs to be sent\r
395 //\r
396 LengthInBytes = pContext->BlockSize;\r
397 if (( pContext->BytesToSend < TFTP_MAX_BLOCK_SIZE )\r
398 && ( LengthInBytes > pContext->BytesToSend )) {\r
399 LengthInBytes = pContext->BytesToSend;\r
400 pContext->bEofSent = TRUE;\r
401 }\r
402 DEBUG (( DEBUG_TX_PACKET,\r
403 "0x%08x: Packet, Block %d filled with %d bytes\r\n",\r
404 pPacket,\r
405 pContext->BlockNumber,\r
406 (UINT32)LengthInBytes ));\r
407 \r
408 //\r
409 // Copy the file data into the packet\r
410 //\r
411 pPacket->TxBytes = (ssize_t)( 2 + 2 + LengthInBytes );\r
412 if ( 0 < LengthInBytes ) {\r
413 CopyMem ( pBuffer,\r
414 pContext->pBuffer,\r
415 (UINTN)LengthInBytes );\r
416 DEBUG (( DEBUG_FILE_BUFFER,\r
417 "0x%08x: Buffer consumed %d bytes of file data\r\n",\r
418 pContext->pBuffer,\r
419 LengthInBytes ));\r
420\r
421 //\r
422 // Account for the file data consumed\r
423 //\r
424 pContext->ValidBytes -= LengthInBytes;\r
425 pContext->BytesToSend -= LengthInBytes;\r
426 pContext->pBuffer += LengthInBytes;\r
427 if ( pContext->pEnd <= pContext->pBuffer ) {\r
428 pContext->pBuffer = &pContext->FileData[ 0 ];\r
429 }\r
430 }\r
431 \r
432 //\r
433 // Queue the packet for transmission\r
7dc13291 434 //\r
f6e5cdd5 435 PacketQueue ( pContext, pPacket );\r
7dc13291 436 }\r
437\r
f6e5cdd5 438 //\r
439 // Return the read status\r
440 //\r
7dc13291 441 DBG_EXIT ( );\r
f6e5cdd5 442 return bReadError;\r
7dc13291 443}\r
444\r
445\r
446/**\r
f6e5cdd5 447 Free the packet\r
7dc13291 448\r
f6e5cdd5 449 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
450 @param [in] pPacket Address of a ::TFTP_PACKET structure\r
7dc13291 451\r
452**/\r
453VOID\r
f6e5cdd5 454PacketFree(\r
455 IN TSDT_CONNECTION_CONTEXT * pContext,\r
456 IN TFTP_PACKET * pPacket\r
7dc13291 457 )\r
458{\r
f6e5cdd5 459 DBG_ENTER ( );\r
7dc13291 460\r
461 //\r
f6e5cdd5 462 // Don't free the error packet\r
7dc13291 463 //\r
f6e5cdd5 464 if ( pPacket != &pContext->ErrorPacket ) {\r
7dc13291 465 //\r
f6e5cdd5 466 // Place the packet on the free list\r
7dc13291 467 //\r
f6e5cdd5 468 pPacket->pNext = pContext->pFreeList;\r
469 pContext->pFreeList = pPacket;\r
470 DEBUG (( DEBUG_TX_PACKET,\r
471 "0x%08x: Packet queued to free list\r\n",\r
472 pPacket ));\r
7dc13291 473 }\r
474\r
f6e5cdd5 475 DBG_EXIT ( );\r
7dc13291 476}\r
477\r
478\r
479/**\r
f6e5cdd5 480 Get a packet from the free list for transmission\r
7dc13291 481\r
f6e5cdd5 482 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
7dc13291 483\r
f6e5cdd5 484 @retval Address of a ::TFTP_PACKET structure\r
7dc13291 485\r
486**/\r
f6e5cdd5 487TFTP_PACKET *\r
488PacketGet (\r
489 IN TSDT_CONNECTION_CONTEXT * pContext\r
7dc13291 490 )\r
491{\r
f6e5cdd5 492 TFTP_PACKET * pPacket;\r
493\r
494 DBG_ENTER ( );\r
495\r
7dc13291 496 //\r
f6e5cdd5 497 // Get the next packet from the free list\r
7dc13291 498 //\r
f6e5cdd5 499 pPacket = pContext->pFreeList;\r
500 if ( NULL != pPacket ) {\r
501 pContext->pFreeList = pPacket->pNext;\r
502 pPacket->RetryCount = 0;\r
503 DEBUG (( DEBUG_TX_PACKET,\r
504 "0x%08x: Packet removed from free list\r\n",\r
505 pPacket ));\r
7dc13291 506 }\r
507\r
508 //\r
f6e5cdd5 509 // Return the packet\r
7dc13291 510 //\r
f6e5cdd5 511 DBG_EXIT_HEX ( pPacket );\r
512 return pPacket;\r
7dc13291 513}\r
514\r
515\r
516/**\r
f6e5cdd5 517 Queue the packet for transmission\r
7dc13291 518\r
f6e5cdd5 519 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
520 @param [in] pPacket Address of a ::TFTP_PACKET structure\r
7dc13291 521\r
f6e5cdd5 522 @retval TRUE if a transmission error has occurred\r
7dc13291 523\r
524**/\r
f6e5cdd5 525BOOLEAN\r
526PacketQueue (\r
527 IN TSDT_CONNECTION_CONTEXT * pContext,\r
528 IN TFTP_PACKET * pPacket\r
7dc13291 529 )\r
530{\r
f6e5cdd5 531 BOOLEAN bTransmitError;\r
532 TFTP_PACKET * pTail;\r
533 EFI_STATUS Status;\r
534\r
535 DBG_ENTER ( );\r
7dc13291 536\r
537 //\r
f6e5cdd5 538 // Account for this data block\r
7dc13291 539 //\r
f6e5cdd5 540 pPacket->BlockNumber = pContext->BlockNumber;\r
541 pContext->BlockNumber += 1;\r
7dc13291 542\r
f6e5cdd5 543 //\r
544 // Queue the packet for transmission\r
545 //\r
546 pTail = pContext->pTxTail;\r
547 if ( NULL == pTail ) {\r
548 pContext->pTxHead = pPacket;\r
549 }\r
550 else {\r
551 pTail->pNext = pPacket;\r
552 }\r
553 pContext->pTxTail = pPacket;\r
554 pPacket->pNext = NULL;\r
555 DEBUG (( DEBUG_TX_PACKET,\r
556 "0x%08x: Packet queued to TX list\r\n",\r
557 pPacket ));\r
7dc13291 558\r
f6e5cdd5 559 //\r
560 // Start the transmission if necessary\r
561 //\r
562 bTransmitError = FALSE;\r
563 if ( pContext->PacketsInWindow < pContext->WindowSize ) {\r
564 Status = PacketTx ( pContext, pPacket );\r
565 bTransmitError = (BOOLEAN)( EFI_ERROR ( Status ));\r
566 }\r
567\r
568 //\r
569 // Return the transmit status\r
570 //\r
571 DBG_EXIT_TF ( bTransmitError );\r
572 return bTransmitError;\r
573}\r
574\r
575\r
576/**\r
577 Remove a packet from the transmit queue\r
578\r
579 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
580\r
581**/\r
582TFTP_PACKET *\r
583PacketRemove(\r
584 IN TSDT_CONNECTION_CONTEXT * pContext\r
585 )\r
586{\r
587 TFTP_PACKET * pNext;\r
588 TFTP_PACKET * pPacket;\r
589\r
590 DBG_ENTER ( );\r
591\r
592 //\r
593 // Remove a packet from the transmit queue\r
594 //\r
595 //\r
596 pPacket = pContext->pTxHead;\r
597 if ( NULL != pPacket ) {\r
598 pNext = pPacket->pNext;\r
599 pContext->pTxHead = pNext;\r
600 if ( NULL == pNext ) {\r
601 pContext->pTxTail = NULL;\r
7dc13291 602 }\r
f6e5cdd5 603 DEBUG (( DEBUG_TX_PACKET,\r
604 "0x%08x: Packet removed from TX list\r\n",\r
605 pPacket ));\r
7dc13291 606\r
607 //\r
f6e5cdd5 608 // Remove this packet from the window\r
7dc13291 609 //\r
f6e5cdd5 610 pContext->PacketsInWindow -= 1;\r
611 }\r
7dc13291 612\r
613 //\r
f6e5cdd5 614 // Return the packet\r
7dc13291 615 //\r
f6e5cdd5 616 DBG_EXIT_HEX ( pPacket );\r
617 return pPacket;\r
7dc13291 618}\r
619\r
620\r
621/**\r
f6e5cdd5 622 Transmit the packet\r
7dc13291 623\r
f6e5cdd5 624 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
625 @param [in] pPacket Address of a ::TFTP_PACKET structure\r
7dc13291 626\r
627 @retval EFI_SUCCESS Message processed successfully\r
628\r
629**/\r
630EFI_STATUS\r
f6e5cdd5 631PacketTx (\r
632 IN TSDT_CONNECTION_CONTEXT * pContext,\r
633 IN TFTP_PACKET * pPacket\r
7dc13291 634 )\r
635{\r
f6e5cdd5 636 ssize_t LengthInBytes;\r
7dc13291 637 EFI_STATUS Status;\r
638\r
f6e5cdd5 639 DBG_ENTER ( );\r
640\r
7dc13291 641 //\r
f6e5cdd5 642 // Assume success\r
7dc13291 643 //\r
f6e5cdd5 644 Status = EFI_SUCCESS;\r
645\r
646 //\r
647 // Determine if this packet should be transmitted\r
648 //\r
649 if ( PcdGet32 ( Tftp_MaxRetry ) >= pPacket->RetryCount ) {\r
650 pPacket->RetryCount += 1;\r
651\r
7dc13291 652 //\r
f6e5cdd5 653 // Display the operation\r
7dc13291 654 //\r
f6e5cdd5 655 DEBUG (( DEBUG_TX_PACKET,\r
656 "0x%08x: Packet transmiting\r\n",\r
657 pPacket ));\r
658 DEBUG (( DEBUG_TX,\r
659 "0x%08x: pContext sending 0x%08x bytes\r\n",\r
660 pContext,\r
661 pPacket->TxBytes ));\r
662\r
7dc13291 663 //\r
f6e5cdd5 664 // Keep track of when the packet was transmitted\r
7dc13291 665 //\r
f6e5cdd5 666 if ( PcdGetBool ( Tftp_HighSpeed )) {\r
667 pPacket->TxTime = GetPerformanceCounter ( );\r
668 }\r
7dc13291 669\r
670 //\r
f6e5cdd5 671 // Send the TFTP packet\r
7dc13291 672 //\r
f6e5cdd5 673 pContext->PacketsInWindow += 1;\r
674 LengthInBytes = sendto ( pContext->SocketFd,\r
675 &pPacket->TxBuffer[ 0 ],\r
676 pPacket->TxBytes,\r
677 0,\r
678 (struct sockaddr *)&pContext->RemoteAddress,\r
679 pContext->RemoteAddress.sin6_len );\r
680 if ( -1 == LengthInBytes ) {\r
681 DEBUG (( DEBUG_ERROR | DEBUG_TX,\r
682 "ERROR - Transmit failure, errno: 0x%08x\r\n",\r
683 errno ));\r
684 pContext->PacketsInWindow -= 1;\r
685 Status = EFI_DEVICE_ERROR;\r
686 }\r
687 }\r
688 else {\r
689 //\r
690 // Too many retries\r
691 //\r
692 Status = EFI_NO_RESPONSE;\r
693 DEBUG (( DEBUG_WARN | DEBUG_WINDOW,\r
694 "WARNING - No response from TFTP client\r\n" ));\r
7dc13291 695 }\r
7dc13291 696\r
697 //\r
698 // Return the operation status\r
699 //\r
f6e5cdd5 700 DBG_EXIT_STATUS ( Status );\r
7dc13291 701 return Status;\r
702}\r
703\r
704\r
705/**\r
f6e5cdd5 706 Process the work for the sockets.\r
7dc13291 707\r
f6e5cdd5 708 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
709 @param [in] pIndex Address of an index into the pollfd array\r
7dc13291 710\r
711**/\r
f6e5cdd5 712VOID\r
713PortWork (\r
714 IN TSDT_TFTP_SERVER * pTftpServer,\r
715 IN int * pIndex\r
7dc13291 716 )\r
717{\r
f6e5cdd5 718 int Index;\r
719 TSDT_CONNECTION_CONTEXT * pContext;\r
720 struct pollfd * pTftpPort;\r
721 socklen_t RemoteAddressLength;\r
722 int revents;\r
7dc13291 723\r
f6e5cdd5 724 DBG_ENTER ( );\r
7dc13291 725\r
726 //\r
f6e5cdd5 727 // Locate the port\r
728 //\r
729 Index = *pIndex;\r
730 if ( -1 != Index ) {\r
731 pTftpPort = &pTftpServer->TftpPort[ *pIndex ];\r
732\r
733 //\r
734 // Handle input events\r
735 //\r
736 revents = pTftpPort->revents;\r
737 pTftpPort->revents = 0;\r
738 if ( 0 != ( revents & POLLRDNORM )) {\r
739 //\r
740 // Receive the message from the remote system\r
741 //\r
742 RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress );\r
743 pTftpServer->RxBytes = recvfrom ( pTftpPort->fd,\r
744 &pTftpServer->RxBuffer[ 0 ],\r
745 sizeof ( pTftpServer->RxBuffer ),\r
746 0,\r
747 (struct sockaddr *) &pTftpServer->RemoteAddress,\r
748 &RemoteAddressLength );\r
749 if ( -1 != pTftpServer->RxBytes ) {\r
750 if ( PcdGetBool ( Tftp_HighSpeed )) {\r
751 pTftpServer->RxTime = GetPerformanceCounter ( );\r
752 }\r
753 if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
754 DEBUG (( DEBUG_TFTP_PORT,\r
755 "Received %d bytes from %d.%d.%d.%d:%d\r\n",\r
756 pTftpServer->RxBytes,\r
757 pTftpServer->RemoteAddress.v4.sin_addr.s_addr & 0xff,\r
758 ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ) & 0xff,\r
759 ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ) & 0xff,\r
760 ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ) & 0xff,\r
761 htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
762 }\r
763 else {\r
764 DEBUG (( DEBUG_TFTP_PORT,\r
765 "Received %d bytes from [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
766 pTftpServer->RxBytes,\r
767 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
768 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
769 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
770 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
771 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
772 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
773 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
774 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
775 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
776 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
777 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
778 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
779 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
780 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
781 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
782 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
783 htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
784 }\r
785\r
786 //\r
787 // Lookup connection context using the remote system address and port\r
788 // to determine if an existing connection to this remote\r
789 // system exists\r
790 //\r
791 pContext = ContextFind ( pTftpServer );\r
792\r
793 //\r
794 // Process the received message\r
795 //\r
796 TftpProcessRequest ( pTftpServer, pContext, pTftpPort->fd );\r
797 }\r
798 else {\r
799 //\r
800 // Receive error on the TFTP server port\r
801 // Close the server socket\r
802 //\r
803 DEBUG (( DEBUG_ERROR,\r
804 "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n",\r
805 errno ));\r
806 revents |= POLLHUP;\r
807 }\r
808 }\r
809\r
810 //\r
811 // Handle the close event\r
812 //\r
813 if ( 0 != ( revents & POLLHUP )) {\r
814 //\r
815 // Close the port\r
816 //\r
817 close ( pTftpPort->fd );\r
818 pTftpPort->fd = -1;\r
819 *pIndex = -1;\r
820 pTftpServer->Entries -= 1;\r
821 ASSERT ( 0 <= pTftpServer->Entries );\r
822 }\r
823 }\r
824\r
825 DBG_EXIT ( );\r
826}\r
827\r
828\r
829/**\r
830 Build and send an error packet\r
831\r
832 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
833 @param [in] Error Error number for the packet\r
834 @param [in] pError Zero terminated error string address\r
835\r
836 @retval EFI_SUCCESS Message processed successfully\r
837\r
838**/\r
839EFI_STATUS\r
840SendError (\r
841 IN TSDT_CONNECTION_CONTEXT * pContext,\r
842 IN UINT16 Error,\r
843 IN UINT8 * pError\r
844 )\r
845{\r
846 UINT8 Character;\r
847 UINT8 * pBuffer;\r
848 TFTP_PACKET * pPacket;\r
849 EFI_STATUS Status;\r
850\r
851 DBG_ENTER ( );\r
852\r
853 //\r
854 // Build the error packet\r
855 //\r
856 pPacket = &pContext->ErrorPacket;\r
857 pBuffer = &pPacket->TxBuffer[ 0 ];\r
858 pBuffer[ 0 ] = 0;\r
859 pBuffer[ 1 ] = TFTP_OP_ERROR;\r
860 pBuffer[ 2 ] = (UINT8)( Error >> 8 );\r
861 pBuffer[ 3 ] = (UINT8)Error;\r
862\r
863 //\r
864 // Copy the zero terminated string into the buffer\r
865 //\r
866 pBuffer += 4;\r
867 do {\r
868 Character = *pError++;\r
869 *pBuffer++ = Character;\r
870 } while ( 0 != Character );\r
871\r
872 //\r
873 // Send the error message\r
874 //\r
875 pPacket->TxBytes = pBuffer - &pPacket->TxBuffer[ 0 ];\r
876 Status = PacketTx ( pContext, pPacket );\r
877\r
878 //\r
879 // Return the operation status\r
880 //\r
881 DBG_EXIT_STATUS ( Status );\r
882 return Status;\r
883}\r
884\r
885\r
886/**\r
887 Scan the list of sockets and process any pending work\r
888\r
889 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
890\r
891**/\r
892VOID\r
893SocketPoll (\r
894 IN TSDT_TFTP_SERVER * pTftpServer\r
895 )\r
896{\r
897 int FDCount;\r
898\r
899 DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" ));\r
900\r
901 //\r
902 // Determine if any ports are active\r
903 //\r
904 if ( 0 != pTftpServer->Entries ) {\r
905 FDCount = poll ( &pTftpServer->TftpPort[ 0 ],\r
906 pTftpServer->Entries,\r
907 CLIENT_POLL_DELAY );\r
908 if ( 0 < FDCount ) {\r
909 //\r
910 // Process this port\r
911 //\r
912 PortWork ( pTftpServer, &pTftpServer->Udpv4Index );\r
913 PortWork ( pTftpServer, &pTftpServer->Udpv6Index );\r
914 }\r
915 }\r
916\r
917 DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" ));\r
918}\r
919\r
920\r
921/**\r
922 Process the ACK\r
923\r
924 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
925 @param [in] pContext Connection context structure address\r
926\r
927 @retval TRUE if the context should be closed\r
928\r
929**/\r
930BOOLEAN\r
931TftpAck (\r
932 IN TSDT_TFTP_SERVER * pTftpServer,\r
933 IN TSDT_CONNECTION_CONTEXT * pContext\r
934 )\r
935{\r
936 INTN AckNumber;\r
937 BOOLEAN bCloseContext;\r
938 UINT16 BlockNumber;\r
939 UINT8 * pBuffer;\r
940 TFTP_PACKET * pPacket;\r
941 EFI_STATUS Status;\r
942\r
943 DBG_ENTER ( );\r
944\r
945 //\r
946 // Use break instead of goto\r
947 //\r
948 bCloseContext = FALSE;\r
949 for ( ; ; ) {\r
950 //\r
951 // Validate the parameters\r
952 //\r
953 if ( NULL == pContext ) {\r
954 if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
955 DEBUG (( DEBUG_ERROR,\r
956 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r
957 (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
958 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
959 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
960 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
961 htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
962 }\r
963 else {\r
964 DEBUG (( DEBUG_ERROR,\r
965 "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
966 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
967 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
968 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
969 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
970 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
971 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
972 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
973 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
974 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
975 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
976 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
977 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
978 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
979 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
980 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
981 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
982 htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
983 }\r
984 break;\r
985 }\r
986\r
987 //\r
988 // Verify that the ACK was expected\r
989 //\r
990 pPacket = pContext->pTxHead;\r
991 if ( NULL == pPacket ) {\r
992 //\r
993 // ACK not expected!\r
994 //\r
995 DEBUG (( DEBUG_ERROR,\r
996 "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",\r
997 pContext ));\r
998 break;\r
999 }\r
1000\r
1001 //\r
1002 // Get the ACKed block number\r
1003 //\r
1004 pBuffer = &pTftpServer->RxBuffer[ 0 ];\r
1005 BlockNumber = HTONS ( *(UINT16 *)&pBuffer[ 2 ]);\r
1006\r
1007 //\r
1008 // Determine if this is the correct ACK\r
1009 //\r
1010 DEBUG (( DEBUG_TFTP_ACK,\r
1011 "ACK for block 0x%04x received\r\n",\r
1012 BlockNumber ));\r
1013 AckNumber = BlockNumber - pPacket->BlockNumber;\r
1014 if (( 0 > AckNumber ) || ( AckNumber >= (INTN)pContext->PacketsInWindow )){\r
1015 DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK,\r
1016 "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",\r
1017 pPacket->BlockNumber,\r
1018 BlockNumber ));\r
1019 break;\r
1020 }\r
1021\r
1022 //\r
1023 // Release the ACKed packets\r
1024 //\r
1025 do {\r
1026 //\r
1027 // Remove the packet from the transmit list and window\r
1028 //\r
1029 pPacket = PacketRemove ( pContext );\r
1030\r
1031 //\r
1032 // Get the block number of this packet\r
1033 //\r
1034 AckNumber = pPacket->BlockNumber;\r
1035\r
1036 //\r
1037 // Increase the size of the transmit window\r
1038 //\r
1039 if ( PcdGetBool ( Tftp_HighSpeed )\r
1040 && ( AckNumber == BlockNumber )) {\r
1041 WindowAck ( pTftpServer, pContext, pPacket );\r
1042 }\r
1043\r
1044 //\r
1045 // Free this packet\r
1046 //\r
1047 PacketFree ( pContext, pPacket );\r
1048 } while (( NULL != pContext->pTxHead ) && ( AckNumber != BlockNumber ));\r
1049\r
1050 //\r
1051 // Fill the window with packets\r
1052 //\r
1053 pPacket = pContext->pTxHead;\r
1054 while (( NULL != pPacket )\r
1055 && ( pContext->PacketsInWindow < pContext->WindowSize )\r
1056 && ( !bCloseContext )) {\r
1057 Status = PacketTx ( pContext, pPacket );\r
1058 bCloseContext = (BOOLEAN)( EFI_ERROR ( Status ));\r
1059 pPacket = pPacket->pNext;\r
1060 }\r
1061 \r
1062 //\r
1063 // Get more packets ready for transmission\r
1064 //\r
1065 PacketFill ( pContext );\r
1066\r
1067 //\r
1068 // Close the context when the last packet is ACKed\r
1069 //\r
1070 if ( 0 == pContext->PacketsInWindow ) {\r
1071 bCloseContext = TRUE;\r
1072\r
1073 //\r
1074 // Display the bandwidth\r
1075 //\r
1076 if ( PcdGetBool ( Tftp_Bandwidth )) {\r
1077 UINT64 Bandwidth;\r
1078 UINT64 DeltaTime;\r
1079 UINT64 NanoSeconds;\r
1080 UINT32 Value;\r
1081\r
1082 //\r
1083 // Compute the download time\r
1084 //\r
1085 DeltaTime = GetPerformanceCounter ( );\r
1086 if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r
1087 DeltaTime = DeltaTime - pContext->TimeStart;\r
1088 }\r
1089 else {\r
1090 DeltaTime = pContext->TimeStart - DeltaTime;\r
1091 }\r
1092 NanoSeconds = GetTimeInNanoSecond ( DeltaTime );\r
1093 Bandwidth = pContext->LengthInBytes;\r
1094 DEBUG (( DEBUG_WINDOW,\r
1095 "File Length %Ld, Transfer Time: %d.%03d Sec\r\n",\r
1096 Bandwidth,\r
1097 DivU64x32 ( NanoSeconds, 1000 * 1000 * 1000 ),\r
1098 ((UINT32)DivU64x32 ( NanoSeconds, 1000 * 1000 )) % 1000 ));\r
1099\r
1100 //\r
1101 // Display the round trip time\r
1102 //\r
1103 Bandwidth = MultU64x32 ( Bandwidth, 8 * 1000 * 1000 );\r
1104 Bandwidth /= NanoSeconds;\r
1105 if ( 1000 > Bandwidth ) {\r
1106 Value = (UINT32)Bandwidth;\r
1107 Print ( L"Bandwidth: %d Kbits/Sec\r\n",\r
1108 Value );\r
1109 }\r
1110 else if (( 1000 * 1000 ) > Bandwidth ) {\r
1111 Value = (UINT32)Bandwidth;\r
1112 Print ( L"Bandwidth: %d.%03d Mbits/Sec\r\n",\r
1113 Value / 1000,\r
1114 Value % 1000 );\r
1115 }\r
1116 else {\r
1117 Value = (UINT32)DivU64x32 ( Bandwidth, 1000 );\r
1118 Print ( L"Bandwidth: %d.%03d Gbits/Sec\r\n",\r
1119 Value / 1000,\r
1120 Value % 1000 );\r
1121 }\r
1122 }\r
1123 }\r
1124 break;\r
1125 }\r
1126\r
1127 //\r
1128 // Return the operation status\r
1129 //\r
1130 DBG_EXIT ( );\r
1131 return bCloseContext;\r
1132}\r
1133\r
1134\r
1135/**\r
1136 Get the next TFTP option\r
1137\r
1138 @param [in] pOption Address of a zero terminated option string\r
1139 @param [in] pEnd End of buffer address\r
1140 @param [in] ppNextOption Address to receive the address of the next\r
1141 zero terminated option string\r
1142\r
1143 @retval EFI_SUCCESS Message processed successfully\r
1144\r
1145**/\r
1146EFI_STATUS\r
1147TftpOptionGet (\r
1148 IN UINT8 * pOption,\r
1149 IN UINT8 * pEnd,\r
1150 IN UINT8 ** ppNextOption\r
1151 )\r
1152{\r
1153 UINT8 * pNextOption;\r
1154 EFI_STATUS Status;\r
1155\r
1156 //\r
1157 // Locate the end of the option\r
1158 //\r
1159 pNextOption = pOption;\r
1160 while (( pEnd > pNextOption ) && ( 0 != *pNextOption )) {\r
1161 pNextOption += 1;\r
1162 }\r
1163 if ( pEnd <= pNextOption ) {\r
1164 //\r
1165 // Error - end of buffer reached\r
1166 //\r
1167 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r
1168 "ERROR - Option without zero termination received!\r\n" ));\r
1169 Status = EFI_INVALID_PARAMETER;\r
1170 }\r
1171 else {\r
1172 //\r
1173 // Zero terminated option found\r
1174 //\r
1175 pNextOption += 1;\r
1176\r
1177 //\r
1178 // Display the zero terminated ASCII option string\r
1179 //\r
1180 DEBUG (( DEBUG_TFTP_REQUEST,\r
1181 "Option: %a\r\n",\r
1182 pOption ));\r
1183 Status = EFI_SUCCESS;\r
1184 }\r
1185\r
1186 //\r
1187 // Return the next option address\r
1188 //\r
1189 *ppNextOption = pNextOption;\r
1190\r
1191 //\r
1192 // Return the operation status\r
1193 //\r
1194 return Status;\r
1195}\r
1196\r
1197\r
1198/**\r
1199 Place an option value into the option acknowledgement\r
1200\r
1201 @param [in] pOack Option acknowledgement address\r
1202 @param [in] Value Value to translate into ASCII decimal\r
1203\r
1204 @return Option acknowledgement address\r
1205\r
1206**/\r
1207UINT8 *\r
1208TftpOptionSet (\r
1209 IN UINT8 * pOack,\r
1210 IN UINT64 Value\r
1211 )\r
1212{\r
1213 UINT64 NextValue;\r
1214\r
1215 //\r
1216 // Determine the next value\r
1217 //\r
1218 NextValue = Value / 10;\r
1219\r
1220 //\r
1221 // Supress leading zeros\r
7dc13291 1222 //\r
1223 if ( 0 != NextValue ) {\r
1224 pOack = TftpOptionSet ( pOack, NextValue );\r
1225 }\r
1226\r
1227 //\r
1228 // Output this digit\r
1229 //\r
1230 *pOack++ = (UINT8)( Value - ( NextValue * 10 ) + '0' );\r
1231\r
1232 //\r
1233 // Return the next option acknowledgement location\r
1234 //\r
1235 return pOack;\r
1236}\r
1237\r
1238\r
1239/**\r
1240 Process the TFTP request\r
1241\r
f6e5cdd5 1242 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
7dc13291 1243 @param [in] pOption Address of the first zero terminated option string\r
1244 @param [in] pEnd End of buffer address\r
1245\r
1246**/\r
1247VOID\r
1248TftpOptions (\r
1249 IN TSDT_CONNECTION_CONTEXT * pContext,\r
1250 IN UINT8 * pOption,\r
1251 IN UINT8 * pEnd\r
1252 )\r
1253{\r
1254 UINT8 * pNextOption;\r
1255 UINT8 * pOack;\r
f6e5cdd5 1256 TFTP_PACKET * pPacket;\r
7dc13291 1257 UINT8 * pTemp;\r
1258 UINT8 * pValue;\r
1259 EFI_STATUS Status;\r
1260 INT32 Value;\r
1261\r
f6e5cdd5 1262 //\r
1263 // Get a packet\r
1264 //\r
1265 pPacket = PacketGet ( pContext );\r
1266\r
7dc13291 1267 //\r
1268 // Start the OACK packet\r
1269 // Let the OACK handle the parsing errors\r
1270 // See http://tools.ietf.org/html/rfc2347\r
1271 //\r
f6e5cdd5 1272 pOack = &pPacket->TxBuffer[ 0 ];\r
7dc13291 1273 *pOack++ = 0;\r
1274 *pOack++ = TFTP_OP_OACK;\r
f6e5cdd5 1275 pPacket->TxBytes = 2;\r
1276 pPacket->BlockNumber = 0;\r
7dc13291 1277\r
1278 //\r
1279 // Walk the list of options\r
1280 //\r
1281 do {\r
1282 //\r
1283 // Get the next option, skip junk at end of message\r
1284 //\r
1285 Status = TftpOptionGet ( pOption, pEnd, &pNextOption );\r
1286 if ( !EFI_ERROR ( Status )) {\r
1287 //\r
1288 // Process the option\r
1289 //\r
1290\r
1291 //\r
1292 // blksize - See http://tools.ietf.org/html/rfc2348\r
1293 //\r
1294 pValue = pNextOption;\r
f6e5cdd5 1295 if ( 0 == strcasecmp ((char *)pOption, "blksize" )) {\r
7dc13291 1296 //\r
1297 // Get the value\r
1298 //\r
1299 Status = TftpOptionGet ( pValue, pEnd, &pNextOption );\r
1300 if ( !EFI_ERROR ( Status )) {\r
1301 //\r
1302 // Validate the block size, skip non-numeric block sizes\r
1303 //\r
1304 Status = TftpOptionValue ( pValue, &Value );\r
1305 if ( !EFI_ERROR ( Status )) {\r
1306 //\r
1307 // Propose a smaller block size if necessary\r
1308 //\r
1309 if ( Value > TFTP_MAX_BLOCK_SIZE ) {\r
1310 Value = TFTP_MAX_BLOCK_SIZE;\r
1311 }\r
1312\r
1313 //\r
1314 // Set the new block size\r
1315 //\r
1316 pContext->BlockSize = Value;\r
1317 DEBUG (( DEBUG_TFTP_REQUEST,\r
1318 "Using block size of %d bytes\r\n",\r
1319 pContext->BlockSize ));\r
1320\r
1321 //\r
1322 // Update the OACK\r
1323 //\r
1324 pTemp = pOack;\r
1325 *pOack++ = 'b';\r
1326 *pOack++ = 'l';\r
1327 *pOack++ = 'k';\r
1328 *pOack++ = 's';\r
1329 *pOack++ = 'i';\r
1330 *pOack++ = 'z';\r
1331 *pOack++ = 'e';\r
1332 *pOack++ = 0;\r
1333 pOack = TftpOptionSet ( pOack, pContext->BlockSize );\r
1334 *pOack++ = 0;\r
f6e5cdd5 1335 pPacket->TxBytes += pOack - pTemp;\r
7dc13291 1336 }\r
1337 }\r
1338 }\r
1339\r
1340 //\r
1341 // timeout - See http://tools.ietf.org/html/rfc2349\r
1342 //\r
f6e5cdd5 1343 else if ( 0 == strcasecmp ((char *)pOption, "timeout" )) {\r
7dc13291 1344 //\r
1345 // Get the value\r
1346 //\r
1347 Status = TftpOptionGet ( pValue, pEnd, &pNextOption );\r
1348 if ( !EFI_ERROR ( Status )) {\r
1349 Status = TftpOptionValue ( pValue, &Value );\r
1350 if ( !EFI_ERROR ( Status )) {\r
1351 //\r
1352 // Set the timeout value\r
1353 //\r
f6e5cdd5 1354 pContext->MaxTimeout = Value;\r
7dc13291 1355 DEBUG (( DEBUG_TFTP_REQUEST,\r
1356 "Using timeout of %d seconds\r\n",\r
f6e5cdd5 1357 pContext->MaxTimeout ));\r
7dc13291 1358\r
1359 //\r
1360 // Update the OACK\r
1361 //\r
1362 pTemp = pOack;\r
1363 *pOack++ = 't';\r
1364 *pOack++ = 'i';\r
1365 *pOack++ = 'm';\r
1366 *pOack++ = 'e';\r
1367 *pOack++ = 'o';\r
1368 *pOack++ = 'u';\r
1369 *pOack++ = 't';\r
1370 *pOack++ = 0;\r
f6e5cdd5 1371 pOack = TftpOptionSet ( pOack, pContext->MaxTimeout );\r
7dc13291 1372 *pOack++ = 0;\r
f6e5cdd5 1373 pPacket->TxBytes += pOack - pTemp;\r
7dc13291 1374 }\r
1375 }\r
1376 }\r
1377\r
1378 //\r
1379 // tsize - See http://tools.ietf.org/html/rfc2349\r
1380 //\r
f6e5cdd5 1381 else if ( 0 == strcasecmp ((char *)pOption, "tsize" )) {\r
7dc13291 1382 //\r
1383 // Get the value\r
1384 //\r
1385 Status = TftpOptionGet ( pValue, pEnd, &pNextOption );\r
1386 if ( !EFI_ERROR ( Status )) {\r
1387 Status = TftpOptionValue ( pValue, &Value );\r
1388 if ( !EFI_ERROR ( Status )) {\r
1389 //\r
1390 // Return the file size\r
1391 //\r
1392 DEBUG (( DEBUG_TFTP_REQUEST,\r
1393 "Returning file size of %Ld bytes\r\n",\r
1394 pContext->LengthInBytes ));\r
1395\r
1396 //\r
1397 // Update the OACK\r
1398 //\r
1399 pTemp = pOack;\r
1400 *pOack++ = 't';\r
1401 *pOack++ = 's';\r
1402 *pOack++ = 'i';\r
1403 *pOack++ = 'z';\r
1404 *pOack++ = 'e';\r
1405 *pOack++ = 0;\r
1406 pOack = TftpOptionSet ( pOack, pContext->LengthInBytes );\r
1407 *pOack++ = 0;\r
f6e5cdd5 1408 pPacket->TxBytes += pOack - pTemp;\r
7dc13291 1409 }\r
1410 }\r
1411 }\r
1412 else {\r
1413 //\r
1414 // Unknown option - Ignore it\r
1415 //\r
1416 DEBUG (( DEBUG_WARN | DEBUG_TFTP_REQUEST,\r
1417 "WARNING - Skipping unknown option: %a\r\n",\r
1418 pOption ));\r
1419 }\r
1420 }\r
1421\r
1422 //\r
1423 // Set the next option\r
1424 //\r
1425 pOption = pNextOption;\r
1426 } while ( pEnd > pOption );\r
f6e5cdd5 1427\r
1428 //\r
1429 // Transmit the OACK if necessary\r
1430 //\r
1431 if ( 2 < pPacket->TxBytes ) {\r
1432 PacketQueue ( pContext, pPacket );\r
1433 }\r
1434 else {\r
1435 PacketFree ( pContext, pPacket );\r
1436 }\r
7dc13291 1437}\r
1438\r
1439\r
1440/**\r
1441 Process the TFTP request\r
1442\r
1443 @param [in] pOption Address of the first zero terminated option string\r
1444 @param [in] pValue Address to receive the value\r
1445\r
1446 @retval EFI_SUCCESS Option translated into a value\r
1447\r
1448**/\r
1449EFI_STATUS\r
1450TftpOptionValue (\r
1451 IN UINT8 * pOption,\r
1452 IN INT32 * pValue\r
1453 )\r
1454{\r
1455 UINT8 Digit;\r
1456 EFI_STATUS Status;\r
1457 INT32 Value;\r
1458\r
1459 //\r
1460 // Assume success\r
1461 //\r
1462 Status = EFI_SUCCESS;\r
1463\r
1464 //\r
1465 // Walk the characters in the option\r
1466 //\r
1467 Value = 0;\r
1468 while ( 0 != *pOption ) {\r
1469 //\r
1470 // Convert the next digit to binary\r
1471 //\r
1472 Digit = *pOption++;\r
1473 if (( '0' <= Digit ) && ( '9' >= Digit )) {\r
1474 Value *= 10;\r
1475 Value += Digit - '0';\r
1476 }\r
1477 else {\r
1478 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r
1479 "ERROR - Invalid character '0x%02x' in the value\r\n",\r
1480 Digit ));\r
1481 Status = EFI_INVALID_PARAMETER;\r
1482 break;\r
1483 }\r
1484 }\r
1485\r
1486 //\r
1487 // Return the value\r
1488 //\r
1489 *pValue = Value;\r
1490\r
1491 //\r
1492 // Return the conversion status\r
1493 //\r
1494 return Status;\r
1495}\r
1496\r
1497\r
1498/**\r
1499 Process the TFTP request\r
1500\r
f6e5cdd5 1501 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
1502 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
1503 @param [in] SocketFd Socket file descriptor\r
7dc13291 1504\r
1505**/\r
1506VOID\r
1507TftpProcessRequest (\r
1508 IN TSDT_TFTP_SERVER * pTftpServer,\r
f6e5cdd5 1509 IN TSDT_CONNECTION_CONTEXT * pContext,\r
1510 IN int SocketFd\r
7dc13291 1511 )\r
1512{\r
1513 BOOLEAN bCloseContext;\r
7dc13291 1514 UINT16 Opcode;\r
7dc13291 1515\r
1516 DBG_ENTER ( );\r
1517\r
1518 //\r
1519 // Get the opcode\r
1520 //\r
f6e5cdd5 1521 Opcode = HTONS ( *(UINT16 *)&pTftpServer->RxBuffer[ 0 ]);\r
1522 DEBUG (( DEBUG_TFTP_REQUEST,\r
1523 "TFTP Opcode: 0x%08x\r\n",\r
1524 Opcode ));\r
7dc13291 1525\r
1526 //\r
1527 // Validate the parameters\r
1528 //\r
1529 bCloseContext = FALSE;\r
7dc13291 1530 switch ( Opcode ) {\r
1531 default:\r
1532 DEBUG (( DEBUG_TFTP_REQUEST,\r
1533 "ERROR - Unknown TFTP opcode: %d\r\n",\r
1534 Opcode ));\r
f6e5cdd5 1535 break;\r
1536\r
1537 case TFTP_OP_ACK:\r
1538 bCloseContext = TftpAck ( pTftpServer, pContext );\r
7dc13291 1539 break;\r
1540\r
1541 case TFTP_OP_READ_REQUEST:\r
f6e5cdd5 1542 bCloseContext = TftpRead ( pTftpServer, pContext, SocketFd );\r
7dc13291 1543 break;\r
1544\r
f6e5cdd5 1545\r
1546\r
1547 \r
7dc13291 1548 case TFTP_OP_DATA:\r
1549 if ( NULL == pContext ) {\r
f6e5cdd5 1550 if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
1551 DEBUG (( DEBUG_ERROR,\r
1552 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r
1553 (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
1554 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
1555 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
1556 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
1557 htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
1558 }\r
1559 else {\r
1560 DEBUG (( DEBUG_ERROR,\r
1561 "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
1562 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
1563 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
1564 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
1565 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
1566 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
1567 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
1568 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
1569 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
1570 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
1571 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
1572 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
1573 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
1574 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
1575 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
1576 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
1577 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
1578 htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
1579 }\r
7dc13291 1580 break;\r
1581 }\r
f6e5cdd5 1582 if ( 0 != pContext->PacketsInWindow ) {\r
7dc13291 1583 DEBUG (( DEBUG_ERROR,\r
1584 "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n",\r
1585 pContext ));\r
7dc13291 1586 break;\r
1587 }\r
59bc0593 1588 if ( pTftpServer->RxBytes > (ssize_t)( pContext->BlockSize + 2 + 2 )) {\r
7dc13291 1589 DEBUG (( DEBUG_ERROR,\r
1590 "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n",\r
1591 pTftpServer->RxBytes - 2 - 2,\r
1592 pContext->BlockSize,\r
1593 pContext ));\r
7dc13291 1594 break;\r
1595 }\r
1596 break;\r
1597\r
1598 case TFTP_OP_ERROR:\r
1599 if ( NULL == pContext ) {\r
f6e5cdd5 1600 if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r
1601 DEBUG (( DEBUG_ERROR,\r
1602 "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r
1603 (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r
1604 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r
1605 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r
1606 (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r
1607 htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r
7dc13291 1608 }\r
1609 else {\r
f6e5cdd5 1610 DEBUG (( DEBUG_ERROR,\r
1611 "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
1612 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r
1613 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r
1614 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r
1615 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r
1616 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r
1617 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r
1618 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r
1619 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r
1620 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r
1621 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r
1622 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r
1623 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r
1624 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r
1625 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r
1626 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r
1627 pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r
1628 htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r
7dc13291 1629 }\r
7dc13291 1630 }\r
f6e5cdd5 1631 break;\r
7dc13291 1632 }\r
1633\r
1634 //\r
1635 // Determine if the context should be closed\r
1636 //\r
1637 if ( bCloseContext ) {\r
1638 ContextRemove ( pTftpServer, pContext );\r
1639 }\r
1640\r
1641 DBG_EXIT ( );\r
1642}\r
1643\r
1644\r
1645/**\r
f6e5cdd5 1646 Process the read request\r
7dc13291 1647\r
f6e5cdd5 1648 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
1649 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
1650 @param [in] SocketFd Socket file descriptor\r
7dc13291 1651\r
f6e5cdd5 1652 @retval TRUE if the context should be closed\r
7dc13291 1653\r
1654**/\r
f6e5cdd5 1655BOOLEAN\r
1656TftpRead (\r
7dc13291 1657 IN TSDT_TFTP_SERVER * pTftpServer,\r
1658 IN TSDT_CONNECTION_CONTEXT * pContext,\r
f6e5cdd5 1659 IN int SocketFd\r
7dc13291 1660 )\r
1661{\r
f6e5cdd5 1662 BOOLEAN bCloseContext;\r
1663 struct stat FileStatus;\r
7dc13291 1664 UINT8 * pBuffer;\r
f6e5cdd5 1665 UINT8 * pEnd;\r
1666 UINT8 * pFileName;\r
1667 UINT8 * pMode;\r
1668 UINT8 * pOption;\r
1669 CHAR8 * pReadMode;\r
1670 UINT64 TimeStart;\r
7dc13291 1671\r
1672 DBG_ENTER ( );\r
1673\r
1674 //\r
f6e5cdd5 1675 // Log the receive time\r
7dc13291 1676 //\r
f6e5cdd5 1677 TimeStart = 0;\r
1678 if ( PcdGetBool ( Tftp_Bandwidth )) {\r
1679 TimeStart = GetPerformanceCounter ( );\r
1680 }\r
7dc13291 1681\r
1682 //\r
f6e5cdd5 1683 // Close the context if necessary\r
7dc13291 1684 //\r
f6e5cdd5 1685 bCloseContext = FALSE;\r
1686 if ( NULL != pContext ) {\r
1687 ContextRemove ( pTftpServer, pContext );\r
1688 }\r
7dc13291 1689\r
1690 //\r
f6e5cdd5 1691 // Use break instead of goto\r
7dc13291 1692 //\r
f6e5cdd5 1693 for ( ; ; ) {\r
1694 //\r
1695 // Create the connection context\r
1696 //\r
1697 pContext = ContextAdd ( pTftpServer, SocketFd );\r
1698 if ( NULL == pContext ) {\r
1699 break;\r
1700 }\r
7dc13291 1701\r
f6e5cdd5 1702 //\r
1703 // Set the start time\r
1704 //\r
1705 if ( PcdGetBool ( Tftp_Bandwidth )) {\r
1706 pContext->TimeStart = TimeStart;\r
1707 }\r
7dc13291 1708\r
f6e5cdd5 1709 //\r
1710 // Locate the mode\r
1711 //\r
1712 pBuffer = &pTftpServer->RxBuffer[ 0 ];\r
1713 pEnd = &pBuffer[ pTftpServer->RxBytes ];\r
1714 pFileName = &pBuffer[ 2 ];\r
1715 pMode = pFileName;\r
1716 while (( pEnd > pMode ) && ( 0 != *pMode )) {\r
1717 pMode += 1;\r
1718 }\r
1719 if ( pEnd <= pMode ) {\r
1720 //\r
1721 // Mode not found\r
1722 //\r
1723 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
1724 "ERROR - File mode not found\r\n" ));\r
1725 //\r
1726 // Tell the client of the error\r
1727 //\r
1728 SendError ( pContext,\r
1729 TFTP_ERROR_SEE_MSG,\r
1730 (UINT8 *)"File open mode not found" );\r
1731 break;\r
1732 }\r
1733 pMode += 1;\r
1734 DEBUG (( DEBUG_TFTP_REQUEST,\r
1735 "TFTP - FileName: %a\r\n",\r
1736 pFileName ));\r
7dc13291 1737\r
f6e5cdd5 1738 //\r
1739 // Locate the options\r
1740 //\r
1741 pOption = pMode;\r
1742 while (( pEnd > pOption ) && ( 0 != *pOption )) {\r
1743 pOption += 1;\r
1744 }\r
1745 if ( pEnd <= pOption ) {\r
1746 //\r
1747 // End of mode not found\r
1748 //\r
1749 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
1750 "ERROR - File mode not valid\r\n" ));\r
1751 //\r
1752 // Tell the client of the error\r
1753 //\r
1754 SendError ( pContext,\r
1755 TFTP_ERROR_SEE_MSG,\r
1756 (UINT8 *)"File open mode not valid" );\r
1757 break;\r
1758 }\r
1759 pOption += 1;\r
1760 DEBUG (( DEBUG_TFTP_REQUEST,\r
1761 "TFTP - Mode: %a\r\n",\r
1762 pMode ));\r
7dc13291 1763\r
f6e5cdd5 1764 //\r
1765 // Verify the mode is supported\r
1766 //\r
1767 pReadMode = "r";\r
1768 if ( 0 == strcasecmp ((char *)pMode, "octet" )) {\r
1769 //\r
1770 // Read the file as binary input\r
1771 //\r
1772 pReadMode = "rb";\r
1773 }\r
7dc13291 1774\r
f6e5cdd5 1775 //\r
1776 // Determine the file length\r
1777 //\r
d3a595ce 1778 pContext->File = fopen ((const char *)pFileName, pReadMode );\r
f6e5cdd5 1779 if (( NULL == pContext->File )\r
d3a595ce 1780 || ( -1 == stat ((const char *)pFileName, &FileStatus ))) {\r
f6e5cdd5 1781 //\r
1782 // File not found\r
1783 //\r
1784 DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r
1785 ( NULL == pContext->File )\r
1786 ? "ERROR - File not found!\r\n"\r
1787 : "ERROR - Unable to determine file %a size!\r\n",\r
1788 pFileName ));\r
7dc13291 1789\r
f6e5cdd5 1790 //\r
1791 // Tell the client of the error\r
1792 //\r
1793 SendError ( pContext,\r
1794 TFTP_ERROR_NOT_FOUND,\r
1795 (UINT8 *)"File not found" );\r
1796 break;\r
1797 }\r
1798 pContext->LengthInBytes = FileStatus.st_size;\r
1799 pContext->BytesRemaining = pContext->LengthInBytes;\r
1800 pContext->BytesToSend = pContext->LengthInBytes;\r
7dc13291 1801\r
f6e5cdd5 1802 //\r
1803 // Display the file size\r
1804 //\r
1805 DEBUG_CODE_BEGIN ( );\r
1806 UINT32 Value;\r
1807\r
1808 if ( 1024 > pContext->LengthInBytes ) {\r
1809 Value = (UINT32)pContext->LengthInBytes;\r
1810 DEBUG (( DEBUG_FILE_BUFFER,\r
1811 "%a size: %d Bytes\r\n",\r
1812 pFileName,\r
1813 Value ));\r
1814 }\r
1815 else if (( 1024 * 1024 ) > pContext->LengthInBytes ) {\r
1816 Value = (UINT32)pContext->LengthInBytes;\r
1817 DEBUG (( DEBUG_FILE_BUFFER,\r
1818 "%a size: %d.%03d KiBytes (%Ld Bytes)\r\n",\r
1819 pFileName,\r
1820 Value / 1024,\r
1821 (( Value % 1024 ) * 1000 ) / 1024,\r
1822 pContext->LengthInBytes ));\r
1823 }\r
1824 else if (( 1024 * 1024 * 1024 ) > pContext->LengthInBytes ) {\r
1825 Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 );\r
1826 DEBUG (( DEBUG_FILE_BUFFER,\r
1827 "%a size: %d.%03d MiBytes (%Ld Bytes)\r\n",\r
1828 pFileName,\r
1829 Value / 1024,\r
1830 (( Value % 1024 ) * 1000 ) / 1024,\r
1831 pContext->LengthInBytes ));\r
1832 }\r
1833 else {\r
1834 Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 * 1024 );\r
1835 DEBUG (( DEBUG_FILE_BUFFER,\r
1836 "%a size: %d.%03d GiBytes (%Ld Bytes)\r\n",\r
1837 pFileName,\r
1838 Value / 1024,\r
1839 (( Value % 1024 ) * 1000 ) / 1024,\r
1840 pContext->LengthInBytes ));\r
1841 }\r
1842 DEBUG_CODE_END ( );\r
7dc13291 1843\r
f6e5cdd5 1844 //\r
1845 // Process the options\r
1846 //\r
1847 if ( pEnd > pOption ) {\r
1848 TftpOptions ( pContext, pOption, pEnd );\r
1849 }\r
1850 else {\r
1851 //\r
1852 // Skip the open ACK\r
1853 //\r
1854 pContext->BlockNumber = 1;\r
1855 }\r
7dc13291 1856\r
f6e5cdd5 1857 //\r
1858 // Send the first packet (OACK or data block)\r
1859 //\r
1860 bCloseContext = PacketFill ( pContext );\r
1861 break;\r
7dc13291 1862 }\r
1863\r
1864 //\r
f6e5cdd5 1865 // Return the close status\r
7dc13291 1866 //\r
f6e5cdd5 1867 DBG_EXIT ( );\r
1868 return bCloseContext;\r
7dc13291 1869}\r
1870\r
1871\r
1872/**\r
1873 Create the port for the TFTP server\r
1874\r
1875 This routine polls the network layer to create the TFTP port for the\r
1876 TFTP server. More than one attempt may be necessary since it may take\r
1877 some time to get the IP address and initialize the upper layers of\r
1878 the network stack.\r
1879\r
f6e5cdd5 1880 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
1881 @param [in] AddressFamily The address family to use for the conection.\r
1882 @param [in] pIndex Address of the index into the port array\r
7dc13291 1883\r
1884**/\r
1885VOID\r
f6e5cdd5 1886TftpServerSocket (\r
1887 IN TSDT_TFTP_SERVER * pTftpServer,\r
1888 IN sa_family_t AddressFamily,\r
1889 IN int * pIndex\r
7dc13291 1890 )\r
1891{\r
7dc13291 1892 int SocketStatus;\r
f6e5cdd5 1893 struct pollfd * pTftpPort;\r
1894 UINT16 TftpPort;\r
1895 union {\r
1896 struct sockaddr_in v4;\r
1897 struct sockaddr_in6 v6;\r
1898 } TftpServerAddress;\r
7dc13291 1899\r
f6e5cdd5 1900 DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerListen\r\n" ));\r
7dc13291 1901\r
1902 //\r
f6e5cdd5 1903 // Determine if the socket is already initialized\r
7dc13291 1904 //\r
f6e5cdd5 1905 if ( -1 == *pIndex ) {\r
7dc13291 1906 //\r
1907 // Attempt to create the socket for the TFTP server\r
1908 //\r
f6e5cdd5 1909 pTftpPort = &pTftpServer->TftpPort[ pTftpServer->Entries ];\r
1910 pTftpPort->fd = socket ( AddressFamily,\r
1911 SOCK_DGRAM,\r
1912 IPPROTO_UDP );\r
1913 if ( -1 != pTftpPort->fd ) {\r
1914 //\r
1915 // Initialize the poll structure\r
1916 //\r
1917 pTftpPort->events = POLLRDNORM | POLLHUP;\r
1918 pTftpPort->revents = 0;\r
1919\r
7dc13291 1920 //\r
1921 // Set the socket address\r
1922 //\r
7dc13291 1923 TftpPort = 69;\r
f6e5cdd5 1924 ZeroMem ( &TftpServerAddress, sizeof ( TftpServerAddress ));\r
1925 TftpServerAddress.v4.sin_port = htons ( TftpPort );\r
1926 if ( AF_INET == AddressFamily ) {\r
1927 TftpServerAddress.v4.sin_len = sizeof ( TftpServerAddress.v4 );\r
1928 TftpServerAddress.v4.sin_family = AF_INET;\r
1929 }\r
1930 else {\r
1931 TftpServerAddress.v6.sin6_len = sizeof ( TftpServerAddress.v6 );\r
1932 TftpServerAddress.v6.sin6_family = AF_INET6;\r
1933 }\r
7dc13291 1934\r
1935 //\r
1936 // Bind the socket to the TFTP port\r
1937 //\r
f6e5cdd5 1938 SocketStatus = bind ( pTftpPort->fd,\r
1939 (struct sockaddr *) &TftpServerAddress,\r
1940 TftpServerAddress.v6.sin6_len );\r
7dc13291 1941 if ( -1 != SocketStatus ) {\r
1942 DEBUG (( DEBUG_TFTP_PORT,\r
1943 "0x%08x: Socket bound to port %d\r\n",\r
f6e5cdd5 1944 pTftpPort->fd,\r
7dc13291 1945 TftpPort ));\r
f6e5cdd5 1946\r
1947 //\r
1948 // Account for this connection\r
1949 //\r
1950 *pIndex = pTftpServer->Entries;\r
1951 pTftpServer->Entries += 1;\r
1952 ASSERT ( DIM ( pTftpServer->TftpPort ) >= pTftpServer->Entries );\r
7dc13291 1953 }\r
1954\r
1955 //\r
1956 // Release the socket if necessary\r
1957 //\r
1958 if ( -1 == SocketStatus ) {\r
f6e5cdd5 1959 close ( pTftpPort->fd );\r
1960 pTftpPort->fd = -1;\r
7dc13291 1961 }\r
1962 }\r
f6e5cdd5 1963 }\r
7dc13291 1964\r
f6e5cdd5 1965 DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerListen\r\n" ));\r
7dc13291 1966}\r
1967\r
1968\r
1969/**\r
f6e5cdd5 1970 Update the window due to the ACK\r
7dc13291 1971\r
f6e5cdd5 1972 @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r
1973 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
1974 @param [in] pPacket Address of a ::TFTP_PACKET structure\r
7dc13291 1975\r
1976**/\r
f6e5cdd5 1977VOID\r
1978WindowAck (\r
1979 IN TSDT_TFTP_SERVER * pTftpServer,\r
1980 IN TSDT_CONNECTION_CONTEXT * pContext,\r
1981 IN TFTP_PACKET * pPacket\r
7dc13291 1982 )\r
1983{\r
f6e5cdd5 1984 if ( PcdGetBool ( Tftp_HighSpeed )) {\r
1985 UINT64 DeltaTime;\r
1986 UINT64 NanoSeconds;\r
7dc13291 1987\r
f6e5cdd5 1988 DBG_ENTER ( );\r
7dc13291 1989\r
7dc13291 1990 //\r
f6e5cdd5 1991 // Compute the round trip time\r
7dc13291 1992 //\r
f6e5cdd5 1993 if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r
1994 DeltaTime = pTftpServer->RxTime - pPacket->TxTime;\r
7dc13291 1995 }\r
1996 else {\r
f6e5cdd5 1997 DeltaTime = pPacket->TxTime - pTftpServer->RxTime;\r
7dc13291 1998 }\r
7dc13291 1999\r
f6e5cdd5 2000 //\r
2001 // Adjust the round trip time\r
2002 //\r
2003 NanoSeconds = GetTimeInNanoSecond ( DeltaTime );\r
2004 DeltaTime = RShiftU64 ( pContext->Rtt2x, ACK_SHIFT );\r
2005 pContext->Rtt2x += NanoSeconds + NanoSeconds - DeltaTime;\r
2006 if ( pContext->Rtt2x > pContext->MaxTimeout ) {\r
2007 pContext->Rtt2x = pContext->MaxTimeout;\r
2008 }\r
2009\r
2010 //\r
2011 // Account for the ACK\r
2012 //\r
2013 if ( pContext->WindowSize < MAX_PACKETS ) {\r
2014 pContext->AckCount -= 1;\r
2015 if ( 0 == pContext->AckCount ) {\r
2016 //\r
2017 // Increase the window\r
2018 //\r
2019 pContext->WindowSize += 1;\r
2020\r
2021 //\r
2022 // Set the ACK count\r
2023 //\r
2024 if ( pContext->WindowSize < pContext->Threshold ) {\r
2025 pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );\r
2026 }\r
2027 else {\r
2028 pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;\r
2029 }\r
2030\r
2031 //\r
2032 // Display the round trip time\r
2033 //\r
2034 DEBUG_CODE_BEGIN ( );\r
2035 UINT32 Value;\r
2036 \r
2037 DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );\r
2038 if ( 1000 > DeltaTime ) {\r
2039 DEBUG (( DEBUG_WINDOW,\r
2040 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",\r
2041 pContext->WindowSize,\r
2042 pContext->Threshold,\r
2043 pContext->AckCount,\r
2044 DeltaTime ));\r
2045 }\r
2046 else if (( 1000 * 1000 ) > DeltaTime ) {\r
2047 Value = (UINT32)DeltaTime;\r
2048 DEBUG (( DEBUG_WINDOW,\r
2049 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",\r
2050 pContext->WindowSize,\r
2051 pContext->Threshold,\r
2052 pContext->AckCount,\r
2053 Value / 1000,\r
2054 Value % 1000 ));\r
2055 }\r
2056 else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {\r
2057 Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );\r
2058 DEBUG (( DEBUG_WINDOW,\r
2059 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",\r
2060 pContext->WindowSize,\r
2061 pContext->Threshold,\r
2062 pContext->AckCount,\r
2063 Value / 1000,\r
2064 Value % 1000 ));\r
2065 }\r
2066 else {\r
2067 Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );\r
2068 DEBUG (( DEBUG_WINDOW,\r
2069 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",\r
2070 pContext->WindowSize,\r
2071 pContext->Threshold,\r
2072 pContext->AckCount,\r
2073 Value / 1000,\r
2074 Value % 1000 ));\r
2075 }\r
2076 DEBUG_CODE_END ( );\r
2077 }\r
2078 }\r
2079\r
2080 DBG_EXIT ( );\r
2081 }\r
7dc13291 2082}\r
2083\r
2084\r
2085/**\r
f6e5cdd5 2086 A timeout has occurred, close the window\r
7dc13291 2087\r
f6e5cdd5 2088 @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r
7dc13291 2089\r
2090**/\r
f6e5cdd5 2091VOID\r
2092WindowTimeout (\r
2093 IN TSDT_CONNECTION_CONTEXT * pContext\r
7dc13291 2094 )\r
2095{\r
f6e5cdd5 2096 if ( PcdGetBool ( Tftp_HighSpeed )) {\r
2097 TFTP_PACKET * pPacket;\r
7dc13291 2098\r
f6e5cdd5 2099 DBG_ENTER ( );\r
7dc13291 2100\r
7dc13291 2101 //\r
f6e5cdd5 2102 // Set the threshold at half the previous window size\r
7dc13291 2103 //\r
f6e5cdd5 2104 pContext->Threshold = ( pContext->WindowSize + 1 ) >> 1;\r
7dc13291 2105\r
f6e5cdd5 2106 //\r
2107 // Close the transmit window\r
2108 //\r
2109 pContext->WindowSize = 1;\r
2110 pContext->PacketsInWindow = 0;\r
2111\r
2112 //\r
2113 // Double the round trip time\r
2114 //\r
2115 pContext->Rtt2x = LShiftU64 ( pContext->Rtt2x, 1 );\r
2116 if ( pContext->Rtt2x > pContext->MaxTimeout ) {\r
2117 pContext->Rtt2x = pContext->MaxTimeout;\r
2118 }\r
2119\r
2120 //\r
2121 // Set the ACK count\r
2122 //\r
2123 if ( pContext->WindowSize < pContext->Threshold ) {\r
2124 pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );\r
7dc13291 2125 }\r
2126 else {\r
f6e5cdd5 2127 pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;\r
7dc13291 2128 }\r
7dc13291 2129\r
f6e5cdd5 2130 //\r
2131 // Display the round trip time\r
2132 //\r
2133 DEBUG_CODE_BEGIN ( );\r
2134 UINT64 DeltaTime;\r
2135 UINT32 Value;\r
2136 \r
2137 DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );\r
2138 if ( 1000 > DeltaTime ) {\r
2139 DEBUG (( DEBUG_WINDOW,\r
2140 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",\r
2141 pContext->WindowSize,\r
2142 pContext->Threshold,\r
2143 pContext->AckCount,\r
2144 DeltaTime ));\r
2145 }\r
2146 else if (( 1000 * 1000 ) > DeltaTime ) {\r
2147 Value = (UINT32)DeltaTime;\r
2148 DEBUG (( DEBUG_WINDOW,\r
2149 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",\r
2150 pContext->WindowSize,\r
2151 pContext->Threshold,\r
2152 pContext->AckCount,\r
2153 Value / 1000,\r
2154 Value % 1000 ));\r
2155 }\r
2156 else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {\r
2157 Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );\r
2158 DEBUG (( DEBUG_WINDOW,\r
2159 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",\r
2160 pContext->WindowSize,\r
2161 pContext->Threshold,\r
2162 pContext->AckCount,\r
2163 Value / 1000,\r
2164 Value % 1000 ));\r
2165 }\r
2166 else {\r
2167 Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );\r
2168 DEBUG (( DEBUG_WINDOW,\r
2169 "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",\r
2170 pContext->WindowSize,\r
2171 pContext->Threshold,\r
2172 pContext->AckCount,\r
2173 Value / 1000,\r
2174 Value % 1000 ));\r
2175 }\r
2176 DEBUG_CODE_END ( );\r
7dc13291 2177\r
f6e5cdd5 2178 //\r
2179 // Retransmit the first packet in the window\r
2180 //\r
2181 pPacket = pContext->pTxHead;\r
2182 if ( NULL != pPacket ) {\r
2183 PacketTx ( pContext, pPacket );\r
2184 }\r
2185 \r
2186 DBG_EXIT ( );\r
7dc13291 2187 }\r
7dc13291 2188}\r
2189\r
2190\r
2191/**\r
2192 Entry point for the TFTP server application.\r
2193\r
2194 @param [in] Argc The number of arguments\r
2195 @param [in] Argv The argument value array\r
2196\r
2197 @retval 0 The application exited normally.\r
2198 @retval Other An error occurred.\r
2199**/\r
2200int\r
2201main (\r
2202 IN int Argc,\r
2203 IN char **Argv\r
2204 )\r
2205{\r
f6e5cdd5 2206 UINTN Index;\r
7dc13291 2207 TSDT_TFTP_SERVER * pTftpServer;\r
2208 EFI_STATUS Status;\r
f6e5cdd5 2209 UINT64 TriggerTime;\r
7dc13291 2210\r
2211 //\r
f6e5cdd5 2212 // Get the performance counter characteristics\r
7dc13291 2213 //\r
2214 pTftpServer = &mTftpServer;\r
f6e5cdd5 2215 if ( PcdGetBool ( Tftp_HighSpeed )\r
2216 || PcdGetBool ( Tftp_Bandwidth )) {\r
2217 pTftpServer->ClockFrequency = GetPerformanceCounterProperties ( &pTftpServer->Time1,\r
2218 &pTftpServer->Time2 );\r
2219 }\r
2220\r
2221 //\r
2222 // Create a timer event to start TFTP port\r
2223 //\r
7dc13291 2224 Status = gBS->CreateEvent ( EVT_TIMER,\r
2225 TPL_TFTP_SERVER,\r
2226 NULL,\r
2227 NULL,\r
2228 &pTftpServer->TimerEvent );\r
2229 if ( !EFI_ERROR ( Status )) {\r
f6e5cdd5 2230 //\r
2231 // Compute the poll interval\r
2232 //\r
2233 TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 );\r
2234 Status = gBS->SetTimer ( pTftpServer->TimerEvent,\r
2235 TimerPeriodic,\r
2236 TriggerTime );\r
7dc13291 2237 if ( !EFI_ERROR ( Status )) {\r
f6e5cdd5 2238 DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" ));\r
2239\r
7dc13291 2240 //\r
2241 // Run the TFTP server forever\r
2242 //\r
f6e5cdd5 2243 pTftpServer->Udpv4Index = -1;\r
2244 pTftpServer->Udpv6Index = -1;\r
2245 do {\r
7dc13291 2246 //\r
2247 // Poll the network layer to create the TFTP port\r
2248 // for the tftp server. More than one attempt may\r
2249 // be necessary since it may take some time to get\r
2250 // the IP address and initialize the upper layers\r
2251 // of the network stack.\r
2252 //\r
f6e5cdd5 2253 if ( DIM ( pTftpServer->TftpPort ) != pTftpServer->Entries ) {\r
2254 do {\r
2255 //\r
2256 // Wait a while before polling for a connection\r
2257 //\r
2258 if ( EFI_SUCCESS != gBS->CheckEvent ( pTftpServer->TimerEvent )) {\r
2259 if ( 0 == pTftpServer->Entries ) {\r
2260 break;\r
2261 }\r
2262 gBS->WaitForEvent ( 1, &pTftpServer->TimerEvent, &Index );\r
2263 }\r
2264\r
2265 //\r
2266 // Poll for a network connection\r
2267 //\r
2268 TftpServerSocket ( pTftpServer,\r
2269 AF_INET,\r
2270 &pTftpServer->Udpv4Index );\r
2271 TftpServerSocket ( pTftpServer,\r
2272 AF_INET6,\r
2273 &pTftpServer->Udpv6Index );\r
2274 } while ( 0 == pTftpServer->Entries );\r
2275 }\r
7dc13291 2276\r
2277 //\r
2278 // Poll the socket for activity\r
2279 //\r
2280 do {\r
2281 SocketPoll ( pTftpServer );\r
7dc13291 2282\r
f6e5cdd5 2283 //\r
2284 // Normal TFTP lets the client request the retransmit by\r
2285 // sending another ACK for the previous packet\r
2286 //\r
2287 if ( PcdGetBool ( Tftp_HighSpeed )) {\r
2288 UINT64 CurrentTime;\r
2289 UINT64 ElapsedTime;\r
2290 TSDT_CONNECTION_CONTEXT * pContext;\r
2291 TFTP_PACKET * pPacket;\r
2292\r
2293 //\r
2294 // High speed TFTP uses an agressive retransmit to\r
2295 // get the TFTP client moving again when the ACK or\r
2296 // previous data packet was lost.\r
2297 //\r
2298 // Get the current time\r
2299 //\r
2300 CurrentTime = GetPerformanceCounter ( );\r
2301\r
2302 //\r
2303 // Walk the list of contexts\r
2304 //\r
2305 pContext = pTftpServer->pContextList;\r
2306 while ( NULL != pContext )\r
2307 {\r
2308 //\r
2309 // Check for a transmit timeout\r
2310 //\r
2311 pPacket = pContext->pTxHead;\r
2312 if ( NULL != pPacket ) {\r
2313 //\r
2314 // Compute the elapsed time\r
2315 //\r
2316 if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r
2317 ElapsedTime = CurrentTime - pPacket->TxTime;\r
2318 }\r
2319 else {\r
2320 ElapsedTime = pPacket->TxTime - CurrentTime;\r
2321 }\r
2322 ElapsedTime = GetTimeInNanoSecond ( ElapsedTime );\r
2323\r
2324 //\r
2325 // Determine if a retransmission is necessary\r
2326 //\r
2327 if ( ElapsedTime >= pContext->Rtt2x ) {\r
2328 DEBUG (( DEBUG_WINDOW,\r
2329 "0x%08x: Context TX timeout for packet 0x%08x, Window: %d\r\n",\r
2330 pContext,\r
2331 pPacket,\r
2332 pContext->WindowSize ));\r
2333 WindowTimeout ( pContext );\r
2334 }\r
2335 }\r
2336\r
2337 //\r
2338 // Set the next context\r
2339 //\r
2340 pContext = pContext->pNext;\r
2341 }\r
2342 }\r
2343 } while ( DIM ( pTftpServer->TftpPort ) == pTftpServer->Entries );\r
2344 } while ( !mbTftpServerExit );\r
7dc13291 2345\r
2346 //\r
2347 // Done with the timer event\r
2348 //\r
f6e5cdd5 2349 gBS->SetTimer ( pTftpServer->TimerEvent,\r
2350 TimerCancel,\r
2351 0 );\r
7dc13291 2352 }\r
f6e5cdd5 2353 gBS->CloseEvent ( pTftpServer->TimerEvent );\r
7dc13291 2354 }\r
2355\r
2356 //\r
2357 // Return the final status\r
2358 //\r
2359 DBG_EXIT_STATUS ( Status );\r
2360 return Status;\r
2361}\r