]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c
Add 'file not found' debug message to MTFTP.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Support.c
CommitLineData
772db4bb 1/** @file\r
dab714aa 2 Support routines for Mtftp.\r
3 \r
f1f11ea2 4Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
772db4bb 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
dab714aa 8http://opensource.org/licenses/bsd-license.php<BR>\r
772db4bb 9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
772db4bb 13**/\r
14\r
15#include "Mtftp4Impl.h"\r
16\r
17\r
18/**\r
dab714aa 19 Allocate a MTFTP4 block range, then init it to the range of [Start, End]\r
772db4bb 20\r
21 @param Start The start block number\r
22 @param End The last block number in the range\r
23\r
dab714aa 24 @return Pointer to the created block range, NULL if failed to allocate memory.\r
772db4bb 25\r
26**/\r
772db4bb 27MTFTP4_BLOCK_RANGE *\r
28Mtftp4AllocateRange (\r
29 IN UINT16 Start,\r
30 IN UINT16 End\r
31 )\r
32{\r
33 MTFTP4_BLOCK_RANGE *Range;\r
34\r
f1f11ea2 35 Range = AllocateZeroPool (sizeof (MTFTP4_BLOCK_RANGE));\r
772db4bb 36\r
37 if (Range == NULL) {\r
38 return NULL;\r
39 }\r
40\r
e48e37fc 41 InitializeListHead (&Range->Link);\r
772db4bb 42 Range->Start = Start;\r
43 Range->End = End;\r
f1f11ea2 44 Range->Bound = End;\r
772db4bb 45\r
46 return Range;\r
47}\r
48\r
49\r
50/**\r
dab714aa 51 Initialize the block range for either RRQ or WRQ. \r
52 \r
53 RRQ and WRQ have different requirements for Start and End. \r
54 For example, during start up, WRQ initializes its whole valid block range \r
55 to [0, 0xffff]. This is bacause the server will send us a ACK0 to inform us \r
56 to start the upload. When the client received ACK0, it will remove 0 from the \r
57 range, get the next block number, which is 1, then upload the BLOCK1. For RRQ\r
58 without option negotiation, the server will directly send us the BLOCK1 in \r
59 response to the client's RRQ. When received BLOCK1, the client will remove \r
60 it from the block range and send an ACK. It also works if there is option \r
61 negotiation.\r
772db4bb 62\r
63 @param Head The block range head to initialize\r
64 @param Start The Start block number.\r
65 @param End The last block number.\r
66\r
67 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range\r
68 @retval EFI_SUCCESS The initial block range is created.\r
69\r
70**/\r
71EFI_STATUS\r
72Mtftp4InitBlockRange (\r
e48e37fc 73 IN LIST_ENTRY *Head,\r
772db4bb 74 IN UINT16 Start,\r
75 IN UINT16 End\r
76 )\r
77{\r
78 MTFTP4_BLOCK_RANGE *Range;\r
79\r
80 Range = Mtftp4AllocateRange (Start, End);\r
81\r
82 if (Range == NULL) {\r
83 return EFI_OUT_OF_RESOURCES;\r
84 }\r
85\r
e48e37fc 86 InsertTailList (Head, &Range->Link);\r
772db4bb 87 return EFI_SUCCESS;\r
88}\r
89\r
90\r
91/**\r
92 Get the first valid block number on the range list.\r
93\r
94 @param Head The block range head\r
95\r
dab714aa 96 @return The first valid block number, -1 if the block range is empty. \r
772db4bb 97\r
98**/\r
99INTN\r
100Mtftp4GetNextBlockNum (\r
e48e37fc 101 IN LIST_ENTRY *Head\r
772db4bb 102 )\r
103{\r
104 MTFTP4_BLOCK_RANGE *Range;\r
105\r
e48e37fc 106 if (IsListEmpty (Head)) {\r
772db4bb 107 return -1;\r
108 }\r
109\r
110 Range = NET_LIST_HEAD (Head, MTFTP4_BLOCK_RANGE, Link);\r
111 return Range->Start;\r
112}\r
113\r
114\r
115/**\r
dab714aa 116 Set the last block number of the block range list. \r
117 \r
118 It will remove all the blocks after the Last. MTFTP initialize the block range\r
119 to the maximum possible range, such as [0, 0xffff] for WRQ. When it gets the \r
120 last block number, it will call this function to set the last block number.\r
772db4bb 121\r
122 @param Head The block range list\r
123 @param Last The last block number\r
124\r
772db4bb 125**/\r
126VOID\r
127Mtftp4SetLastBlockNum (\r
e48e37fc 128 IN LIST_ENTRY *Head,\r
772db4bb 129 IN UINT16 Last\r
130 )\r
131{\r
132 MTFTP4_BLOCK_RANGE *Range;\r
133\r
134 //\r
135 // Iterate from the tail to head to remove the block number\r
136 // after the last.\r
137 //\r
e48e37fc 138 while (!IsListEmpty (Head)) {\r
772db4bb 139 Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);\r
140\r
141 if (Range->Start > Last) {\r
e48e37fc 142 RemoveEntryList (&Range->Link);\r
766c7483 143 FreePool (Range);\r
772db4bb 144 continue;\r
145 }\r
146\r
147 if (Range->End > Last) {\r
148 Range->End = Last;\r
149 }\r
150\r
151 return ;\r
152 }\r
153}\r
154\r
155\r
156/**\r
157 Remove the block number from the block range list.\r
158\r
159 @param Head The block range list to remove from\r
160 @param Num The block number to remove\r
49fd66cb 161 @param Completed Whether Num is the last block number\r
f1f11ea2 162 @param TotalBlock The continuous block number in all \r
772db4bb 163\r
164 @retval EFI_NOT_FOUND The block number isn't in the block range list\r
165 @retval EFI_SUCCESS The block number has been removed from the list\r
166 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource\r
167\r
168**/\r
169EFI_STATUS\r
170Mtftp4RemoveBlockNum (\r
e48e37fc 171 IN LIST_ENTRY *Head,\r
f1f11ea2 172 IN UINT16 Num,\r
49fd66cb 173 IN BOOLEAN Completed,\r
f1f11ea2 174 OUT UINT64 *TotalBlock\r
772db4bb 175 )\r
176{\r
177 MTFTP4_BLOCK_RANGE *Range;\r
178 MTFTP4_BLOCK_RANGE *NewRange;\r
e48e37fc 179 LIST_ENTRY *Entry;\r
772db4bb 180\r
181 NET_LIST_FOR_EACH (Entry, Head) {\r
182\r
183 //\r
184 // Each block represents a hole [Start, End] in the file,\r
185 // skip to the first range with End >= Num\r
186 //\r
187 Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);\r
188\r
189 if (Range->End < Num) {\r
190 continue;\r
191 }\r
192\r
193 //\r
194 // There are three different cases for Start\r
195 // 1. (Start > Num) && (End >= Num):\r
196 // because all the holes before this one has the condition of\r
197 // End < Num, so this block number has been removed.\r
198 //\r
199 // 2. (Start == Num) && (End >= Num):\r
200 // Need to increase the Start by one, and if End == Num, this\r
201 // hole has been removed completely, remove it.\r
202 //\r
203 // 3. (Start < Num) && (End >= Num):\r
204 // if End == Num, only need to decrease the End by one because\r
205 // we have (Start < Num) && (Num == End), so (Start <= End - 1).\r
206 // if (End > Num), the hold is splited into two holes, with\r
207 // [Start, Num - 1] and [Num + 1, End].\r
208 //\r
209 if (Range->Start > Num) {\r
210 return EFI_NOT_FOUND;\r
211\r
212 } else if (Range->Start == Num) {\r
213 Range->Start++;\r
214\r
f1f11ea2 215 //\r
216 // Note that: RFC 1350 does not mention block counter roll-over, \r
217 // but several TFTP hosts implement the roll-over be able to accept \r
218 // transfers of unlimited size. There is no consensus, however, whether \r
219 // the counter should wrap around to zero or to one. Many implementations \r
220 // wrap to zero, because this is the simplest to implement. Here we choose \r
221 // this solution.\r
222 //\r
223 *TotalBlock = Num;\r
224 \r
225 if (Range->Round > 0) {\r
cd7bfc2c 226 *TotalBlock += Range->Bound + MultU64x32 ((UINTN) (Range->Round -1), (UINT32) (Range->Bound + 1)) + 1;\r
f1f11ea2 227 }\r
228\r
229 if (Range->Start > Range->Bound) {\r
230 Range->Start = 0;\r
231 Range->Round ++;\r
232 }\r
233\r
49fd66cb 234 if ((Range->Start > Range->End) || Completed) {\r
e48e37fc 235 RemoveEntryList (&Range->Link);\r
766c7483 236 FreePool (Range);\r
772db4bb 237 }\r
238\r
239 return EFI_SUCCESS;\r
240\r
241 } else {\r
242 if (Range->End == Num) {\r
243 Range->End--;\r
244 } else {\r
687a2e5f 245 NewRange = Mtftp4AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);\r
772db4bb 246\r
247 if (NewRange == NULL) {\r
248 return EFI_OUT_OF_RESOURCES;\r
249 }\r
250\r
251 Range->End = Num - 1;\r
252 NetListInsertAfter (&Range->Link, &NewRange->Link);\r
253 }\r
254\r
255 return EFI_SUCCESS;\r
256 }\r
257 }\r
258\r
259 return EFI_NOT_FOUND;\r
260}\r
261\r
262\r
263/**\r
264 Build then transmit the request packet for the MTFTP session.\r
265\r
266 @param Instance The Mtftp session\r
267\r
268 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request\r
269 @retval EFI_SUCCESS The request is built and sent\r
270 @retval Others Failed to transmit the packet.\r
271\r
272**/\r
273EFI_STATUS\r
274Mtftp4SendRequest (\r
275 IN MTFTP4_PROTOCOL *Instance\r
276 )\r
277{\r
278 EFI_MTFTP4_PACKET *Packet;\r
279 EFI_MTFTP4_OPTION *Options;\r
280 EFI_MTFTP4_TOKEN *Token;\r
281 NET_BUF *Nbuf;\r
282 UINT8 *Mode;\r
283 UINT8 *Cur;\r
284 UINT32 Len;\r
285 UINTN Index;\r
687a2e5f 286 UINT32 Len1;\r
287 UINT32 Len2;\r
772db4bb 288\r
289 Token = Instance->Token;\r
290 Options = Token->OptionList;\r
291 Mode = Instance->Token->ModeStr;\r
292\r
293 if (Mode == NULL) {\r
67a58d0f 294 Mode = (UINT8 *) "octet";\r
772db4bb 295 }\r
296\r
297 //\r
298 // Compute the packet length\r
299 //\r
687a2e5f 300 Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Token->Filename);\r
301 Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Mode);\r
302 Len = (Len1 + Len2 + 4);\r
772db4bb 303\r
304 for (Index = 0; Index < Token->OptionCount; Index++) {\r
687a2e5f 305 Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);\r
306 Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);\r
307 Len += Len1 + Len2 + 2;\r
772db4bb 308 }\r
309\r
310 //\r
311 // Allocate a packet then copy the data over\r
312 //\r
313 if ((Nbuf = NetbufAlloc (Len)) == NULL) {\r
314 return EFI_OUT_OF_RESOURCES;\r
315 }\r
316\r
317 Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);\r
894d038a 318 ASSERT (Packet != NULL);\r
319\r
772db4bb 320 Packet->OpCode = HTONS (Instance->Operation);\r
321 Cur = Packet->Rrq.Filename;\r
687a2e5f 322 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Token->Filename);\r
b7d3c631 323 Cur += AsciiStrLen ((CHAR8 *) Token->Filename) + 1;\r
687a2e5f 324 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Mode);\r
b7d3c631 325 Cur += AsciiStrLen ((CHAR8 *) Mode) + 1;\r
772db4bb 326\r
327 for (Index = 0; Index < Token->OptionCount; ++Index) {\r
b61439a7 328 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].OptionStr);\r
b7d3c631 329 Cur += AsciiStrLen ((CHAR8 *) Options[Index].OptionStr) + 1;\r
b61439a7 330\r
331 Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].ValueStr);\r
b7d3c631 332 Cur += AsciiStrLen ((CHAR8 *) (CHAR8 *) Options[Index].ValueStr) + 1;\r
772db4bb 333 }\r
334\r
335 return Mtftp4SendPacket (Instance, Nbuf);\r
336}\r
337\r
338\r
339/**\r
dab714aa 340 Build then send an error message.\r
772db4bb 341\r
342 @param Instance The MTFTP session\r
dab714aa 343 @param ErrCode The error code \r
344 @param ErrInfo The error message\r
772db4bb 345\r
346 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet\r
347 @retval EFI_SUCCESS The error packet is transmitted.\r
348 @retval Others Failed to transmit the packet.\r
349\r
350**/\r
351EFI_STATUS\r
352Mtftp4SendError (\r
353 IN MTFTP4_PROTOCOL *Instance,\r
354 IN UINT16 ErrCode,\r
dab714aa 355 IN UINT8 *ErrInfo\r
772db4bb 356 )\r
357{\r
358 NET_BUF *Packet;\r
359 EFI_MTFTP4_PACKET *TftpError;\r
360 UINT32 Len;\r
361\r
687a2e5f 362 Len = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));\r
772db4bb 363 Packet = NetbufAlloc (Len);\r
772db4bb 364 if (Packet == NULL) {\r
365 return EFI_OUT_OF_RESOURCES;\r
366 }\r
367\r
368 TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);\r
894d038a 369 ASSERT (TftpError != NULL);\r
370\r
772db4bb 371 TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);\r
372 TftpError->Error.ErrorCode = HTONS (ErrCode);\r
373\r
687a2e5f 374 AsciiStrCpy ((CHAR8 *) TftpError->Error.ErrorMessage, (CHAR8 *) ErrInfo);\r
772db4bb 375\r
376 return Mtftp4SendPacket (Instance, Packet);\r
377}\r
378\r
379\r
380/**\r
381 The callback function called when the packet is transmitted.\r
dab714aa 382 \r
772db4bb 383 It simply frees the packet.\r
384\r
385 @param Packet The transmitted (or failed to) packet\r
b45b45b2 386 @param EndPoint The local and remote UDP access point\r
772db4bb 387 @param IoStatus The result of the transmission\r
388 @param Context Opaque parameter to the callback\r
389\r
772db4bb 390**/\r
772db4bb 391VOID\r
e798cd87 392EFIAPI\r
772db4bb 393Mtftp4OnPacketSent (\r
3dc3861a 394 IN NET_BUF *Packet,\r
b45b45b2 395 IN UDP_END_POINT *EndPoint,\r
3dc3861a 396 IN EFI_STATUS IoStatus,\r
397 IN VOID *Context\r
772db4bb 398 )\r
399{\r
400 NetbufFree (Packet);\r
401}\r
402\r
403\r
404/**\r
dab714aa 405 Set the timeout for the instance. User a longer time for passive instances.\r
772db4bb 406\r
407 @param Instance The Mtftp session to set time out\r
408\r
772db4bb 409**/\r
410VOID\r
411Mtftp4SetTimeout (\r
dab714aa 412 IN OUT MTFTP4_PROTOCOL *Instance\r
772db4bb 413 )\r
414{\r
415 if (Instance->Master) {\r
416 Instance->PacketToLive = Instance->Timeout;\r
417 } else {\r
418 Instance->PacketToLive = Instance->Timeout * 2;\r
419 }\r
420}\r
421\r
422\r
423/**\r
dab714aa 424 Send the packet for the instance. \r
425 \r
426 It will first save a reference to the packet for later retransmission. \r
427 Then determine the destination port, listen port for requests, and connected \r
428 port for others. At last, send the packet out.\r
772db4bb 429\r
430 @param Instance The Mtftp instance\r
431 @param Packet The packet to send\r
432\r
433 @retval EFI_SUCCESS The packet is sent out\r
434 @retval Others Failed to transmit the packet.\r
435\r
436**/\r
437EFI_STATUS\r
438Mtftp4SendPacket (\r
dab714aa 439 IN OUT MTFTP4_PROTOCOL *Instance,\r
440 IN OUT NET_BUF *Packet\r
772db4bb 441 )\r
442{\r
b45b45b2 443 UDP_END_POINT UdpPoint;\r
772db4bb 444 EFI_STATUS Status;\r
445 UINT16 OpCode;\r
16cd325f 446 UINT8 *Buffer;\r
772db4bb 447\r
448 //\r
449 // Save the packet for retransmission\r
450 //\r
451 if (Instance->LastPacket != NULL) {\r
452 NetbufFree (Instance->LastPacket);\r
453 }\r
454\r
b45b45b2 455 Instance->LastPacket = Packet;\r
772db4bb 456\r
b45b45b2 457 Instance->CurRetry = 0;\r
772db4bb 458 Mtftp4SetTimeout (Instance);\r
459\r
b45b45b2 460 ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
461 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
772db4bb 462\r
463 //\r
464 // Send the requests to the listening port, other packets\r
465 // to the connected port\r
466 //\r
16cd325f
ED
467 Buffer = NetbufGetByte (Packet, 0, NULL);\r
468 ASSERT (Buffer != NULL);\r
469 OpCode = NTOHS (*(UINT16 *)Buffer);\r
772db4bb 470\r
dab714aa 471 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || \r
472 (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
772db4bb 473 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
474 UdpPoint.RemotePort = Instance->ListeningPort;\r
475 } else {\r
476 UdpPoint.RemotePort = Instance->ConnectedPort;\r
477 }\r
478\r
479 NET_GET_REF (Packet);\r
480\r
481 Status = UdpIoSendDatagram (\r
482 Instance->UnicastPort,\r
483 Packet,\r
484 &UdpPoint,\r
b45b45b2 485 NULL,\r
772db4bb 486 Mtftp4OnPacketSent,\r
487 Instance\r
488 );\r
489\r
490 if (EFI_ERROR (Status)) {\r
491 NET_PUT_REF (Packet);\r
492 }\r
493\r
494 return Status;\r
495}\r
496\r
497\r
498/**\r
dab714aa 499 Retransmit the last packet for the instance.\r
772db4bb 500\r
501 @param Instance The Mtftp instance\r
502\r
503 @retval EFI_SUCCESS The last packet is retransmitted.\r
504 @retval Others Failed to retransmit.\r
505\r
506**/\r
507EFI_STATUS\r
508Mtftp4Retransmit (\r
509 IN MTFTP4_PROTOCOL *Instance\r
510 )\r
511{\r
b45b45b2 512 UDP_END_POINT UdpPoint;\r
772db4bb 513 EFI_STATUS Status;\r
514 UINT16 OpCode;\r
16cd325f 515 UINT8 *Buffer;\r
772db4bb 516\r
517 ASSERT (Instance->LastPacket != NULL);\r
518\r
b45b45b2 519 ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
520 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
772db4bb 521\r
522 //\r
523 // Set the requests to the listening port, other packets to the connected port\r
524 //\r
16cd325f
ED
525 Buffer = NetbufGetByte (Instance->LastPacket, 0, NULL);\r
526 ASSERT (Buffer != NULL);\r
527 OpCode = NTOHS (*(UINT16 *) Buffer);\r
772db4bb 528\r
529 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
530 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
531 UdpPoint.RemotePort = Instance->ListeningPort;\r
532 } else {\r
533 UdpPoint.RemotePort = Instance->ConnectedPort;\r
534 }\r
535\r
536 NET_GET_REF (Instance->LastPacket);\r
537\r
538 Status = UdpIoSendDatagram (\r
539 Instance->UnicastPort,\r
540 Instance->LastPacket,\r
541 &UdpPoint,\r
b45b45b2 542 NULL,\r
772db4bb 543 Mtftp4OnPacketSent,\r
544 Instance\r
545 );\r
546\r
547 if (EFI_ERROR (Status)) {\r
548 NET_PUT_REF (Instance->LastPacket);\r
549 }\r
550\r
551 return Status;\r
552}\r
553\r
554\r
555/**\r
556 The timer ticking function for the Mtftp service instance.\r
557\r
558 @param Event The ticking event\r
559 @param Context The Mtftp service instance\r
560\r
772db4bb 561**/\r
562VOID\r
563EFIAPI\r
564Mtftp4OnTimerTick (\r
565 IN EFI_EVENT Event,\r
566 IN VOID *Context\r
567 )\r
568{\r
569 MTFTP4_SERVICE *MtftpSb;\r
e48e37fc 570 LIST_ENTRY *Entry;\r
571 LIST_ENTRY *Next;\r
772db4bb 572 MTFTP4_PROTOCOL *Instance;\r
573 EFI_MTFTP4_TOKEN *Token;\r
574\r
575 MtftpSb = (MTFTP4_SERVICE *) Context;\r
576\r
577 //\r
578 // Iterate through all the children of the Mtftp service instance. Time\r
579 // out the packet. If maximum retries reached, clean the session up.\r
580 //\r
581 NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {\r
582 Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);\r
583\r
584 if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {\r
585 continue;\r
586 }\r
587\r
588 //\r
589 // Call the user's time out handler\r
590 //\r
591 Token = Instance->Token;\r
592\r
593 if ((Token->TimeoutCallback != NULL) &&\r
594 EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {\r
595\r
596 Mtftp4SendError (\r
597 Instance,\r
598 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 599 (UINT8 *) "User aborted the transfer in time out"\r
772db4bb 600 );\r
601\r
602 Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
603 continue;\r
604 }\r
605\r
606 //\r
607 // Retransmit the packet if haven't reach the maxmium retry count,\r
608 // otherwise exit the transfer.\r
609 //\r
610 if (++Instance->CurRetry < Instance->MaxRetry) {\r
611 Mtftp4Retransmit (Instance);\r
612 Mtftp4SetTimeout (Instance);\r
613 } else {\r
614 Mtftp4CleanOperation (Instance, EFI_TIMEOUT);\r
615 continue;\r
616 }\r
617 }\r
618}\r