]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c
MdeModulePkg: Update IP4 stack drivers for classless address unicast check.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Support.c
CommitLineData
772db4bb 1/** @file\r
dab714aa 2 Support routines for Mtftp.\r
3 \r
206b5f51 4Copyright (c) 2006 - 2015, 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
6b6fe3e9 281 RETURN_STATUS Status;\r
772db4bb 282 NET_BUF *Nbuf;\r
283 UINT8 *Mode;\r
284 UINT8 *Cur;\r
772db4bb 285 UINTN Index;\r
6b6fe3e9
ZL
286 UINT32 BufferLength;\r
287 UINTN FileNameLength;\r
288 UINTN ModeLength;\r
289 UINTN OptionStrLength;\r
290 UINTN ValueStrLength;\r
772db4bb 291\r
292 Token = Instance->Token;\r
293 Options = Token->OptionList;\r
294 Mode = Instance->Token->ModeStr;\r
295\r
296 if (Mode == NULL) {\r
67a58d0f 297 Mode = (UINT8 *) "octet";\r
772db4bb 298 }\r
299\r
300 //\r
301 // Compute the packet length\r
302 //\r
6b6fe3e9
ZL
303 FileNameLength = AsciiStrLen ((CHAR8 *) Token->Filename);\r
304 ModeLength = AsciiStrLen ((CHAR8 *) Mode);\r
305 BufferLength = (UINT32) FileNameLength + (UINT32) ModeLength + 4;\r
772db4bb 306\r
307 for (Index = 0; Index < Token->OptionCount; Index++) {\r
6b6fe3e9
ZL
308 OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);\r
309 ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);\r
310 BufferLength += (UINT32) OptionStrLength + (UINT32) ValueStrLength + 2;\r
772db4bb 311 }\r
772db4bb 312 //\r
313 // Allocate a packet then copy the data over\r
314 //\r
6b6fe3e9 315 if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {\r
772db4bb 316 return EFI_OUT_OF_RESOURCES;\r
317 }\r
318\r
6b6fe3e9 319 Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, BufferLength, FALSE);\r
894d038a 320 ASSERT (Packet != NULL);\r
321\r
772db4bb 322 Packet->OpCode = HTONS (Instance->Operation);\r
6b6fe3e9
ZL
323 BufferLength -= sizeof (Packet->OpCode);\r
324 \r
772db4bb 325 Cur = Packet->Rrq.Filename;\r
6b6fe3e9
ZL
326 Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Token->Filename);\r
327 ASSERT_EFI_ERROR (Status);\r
328 BufferLength -= (UINT32) (FileNameLength + 1);\r
329 Cur += FileNameLength + 1;\r
330 Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Mode);\r
331 ASSERT_EFI_ERROR (Status);\r
332 BufferLength -= (UINT32) (ModeLength + 1);\r
333 Cur += ModeLength + 1;\r
772db4bb 334\r
335 for (Index = 0; Index < Token->OptionCount; ++Index) {\r
6b6fe3e9
ZL
336 OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);\r
337 ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);\r
338 \r
339 Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].OptionStr);\r
340 ASSERT_EFI_ERROR (Status);\r
341 BufferLength -= (UINT32) (OptionStrLength + 1);\r
342 Cur += OptionStrLength + 1;\r
343 \r
344 Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].ValueStr);\r
345 ASSERT_EFI_ERROR (Status);\r
346 BufferLength -= (UINT32) (ValueStrLength + 1);\r
347 Cur += ValueStrLength + 1;\r
348 \r
772db4bb 349 }\r
350\r
351 return Mtftp4SendPacket (Instance, Nbuf);\r
352}\r
353\r
354\r
355/**\r
dab714aa 356 Build then send an error message.\r
772db4bb 357\r
358 @param Instance The MTFTP session\r
dab714aa 359 @param ErrCode The error code \r
360 @param ErrInfo The error message\r
772db4bb 361\r
362 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet\r
363 @retval EFI_SUCCESS The error packet is transmitted.\r
364 @retval Others Failed to transmit the packet.\r
365\r
366**/\r
367EFI_STATUS\r
368Mtftp4SendError (\r
369 IN MTFTP4_PROTOCOL *Instance,\r
370 IN UINT16 ErrCode,\r
dab714aa 371 IN UINT8 *ErrInfo\r
772db4bb 372 )\r
373{\r
374 NET_BUF *Packet;\r
375 EFI_MTFTP4_PACKET *TftpError;\r
376 UINT32 Len;\r
377\r
687a2e5f 378 Len = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));\r
772db4bb 379 Packet = NetbufAlloc (Len);\r
772db4bb 380 if (Packet == NULL) {\r
381 return EFI_OUT_OF_RESOURCES;\r
382 }\r
383\r
384 TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);\r
894d038a 385 ASSERT (TftpError != NULL);\r
386\r
772db4bb 387 TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);\r
388 TftpError->Error.ErrorCode = HTONS (ErrCode);\r
389\r
206b5f51 390 AsciiStrCpyS ((CHAR8 *) TftpError->Error.ErrorMessage, Len, (CHAR8 *) ErrInfo);\r
772db4bb 391\r
392 return Mtftp4SendPacket (Instance, Packet);\r
393}\r
394\r
395\r
396/**\r
397 The callback function called when the packet is transmitted.\r
dab714aa 398 \r
772db4bb 399 It simply frees the packet.\r
400\r
401 @param Packet The transmitted (or failed to) packet\r
b45b45b2 402 @param EndPoint The local and remote UDP access point\r
772db4bb 403 @param IoStatus The result of the transmission\r
404 @param Context Opaque parameter to the callback\r
405\r
772db4bb 406**/\r
772db4bb 407VOID\r
e798cd87 408EFIAPI\r
772db4bb 409Mtftp4OnPacketSent (\r
3dc3861a 410 IN NET_BUF *Packet,\r
b45b45b2 411 IN UDP_END_POINT *EndPoint,\r
3dc3861a 412 IN EFI_STATUS IoStatus,\r
413 IN VOID *Context\r
772db4bb 414 )\r
415{\r
416 NetbufFree (Packet);\r
417}\r
418\r
419\r
420/**\r
dab714aa 421 Set the timeout for the instance. User a longer time for passive instances.\r
772db4bb 422\r
423 @param Instance The Mtftp session to set time out\r
424\r
772db4bb 425**/\r
426VOID\r
427Mtftp4SetTimeout (\r
dab714aa 428 IN OUT MTFTP4_PROTOCOL *Instance\r
772db4bb 429 )\r
430{\r
431 if (Instance->Master) {\r
432 Instance->PacketToLive = Instance->Timeout;\r
433 } else {\r
434 Instance->PacketToLive = Instance->Timeout * 2;\r
435 }\r
436}\r
437\r
438\r
439/**\r
dab714aa 440 Send the packet for the instance. \r
441 \r
442 It will first save a reference to the packet for later retransmission. \r
443 Then determine the destination port, listen port for requests, and connected \r
444 port for others. At last, send the packet out.\r
772db4bb 445\r
446 @param Instance The Mtftp instance\r
447 @param Packet The packet to send\r
448\r
449 @retval EFI_SUCCESS The packet is sent out\r
450 @retval Others Failed to transmit the packet.\r
451\r
452**/\r
453EFI_STATUS\r
454Mtftp4SendPacket (\r
dab714aa 455 IN OUT MTFTP4_PROTOCOL *Instance,\r
456 IN OUT NET_BUF *Packet\r
772db4bb 457 )\r
458{\r
b45b45b2 459 UDP_END_POINT UdpPoint;\r
772db4bb 460 EFI_STATUS Status;\r
461 UINT16 OpCode;\r
16cd325f 462 UINT8 *Buffer;\r
772db4bb 463\r
464 //\r
465 // Save the packet for retransmission\r
466 //\r
467 if (Instance->LastPacket != NULL) {\r
468 NetbufFree (Instance->LastPacket);\r
469 }\r
470\r
b45b45b2 471 Instance->LastPacket = Packet;\r
772db4bb 472\r
b45b45b2 473 Instance->CurRetry = 0;\r
772db4bb 474 Mtftp4SetTimeout (Instance);\r
475\r
b45b45b2 476 ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
477 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
772db4bb 478\r
479 //\r
480 // Send the requests to the listening port, other packets\r
481 // to the connected port\r
482 //\r
16cd325f
ED
483 Buffer = NetbufGetByte (Packet, 0, NULL);\r
484 ASSERT (Buffer != NULL);\r
485 OpCode = NTOHS (*(UINT16 *)Buffer);\r
772db4bb 486\r
dab714aa 487 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || \r
488 (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
772db4bb 489 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
490 UdpPoint.RemotePort = Instance->ListeningPort;\r
491 } else {\r
492 UdpPoint.RemotePort = Instance->ConnectedPort;\r
493 }\r
494\r
495 NET_GET_REF (Packet);\r
496\r
497 Status = UdpIoSendDatagram (\r
498 Instance->UnicastPort,\r
499 Packet,\r
500 &UdpPoint,\r
b45b45b2 501 NULL,\r
772db4bb 502 Mtftp4OnPacketSent,\r
503 Instance\r
504 );\r
505\r
506 if (EFI_ERROR (Status)) {\r
507 NET_PUT_REF (Packet);\r
508 }\r
509\r
510 return Status;\r
511}\r
512\r
513\r
514/**\r
dab714aa 515 Retransmit the last packet for the instance.\r
772db4bb 516\r
517 @param Instance The Mtftp instance\r
518\r
519 @retval EFI_SUCCESS The last packet is retransmitted.\r
520 @retval Others Failed to retransmit.\r
521\r
522**/\r
523EFI_STATUS\r
524Mtftp4Retransmit (\r
525 IN MTFTP4_PROTOCOL *Instance\r
526 )\r
527{\r
b45b45b2 528 UDP_END_POINT UdpPoint;\r
772db4bb 529 EFI_STATUS Status;\r
530 UINT16 OpCode;\r
16cd325f 531 UINT8 *Buffer;\r
772db4bb 532\r
533 ASSERT (Instance->LastPacket != NULL);\r
534\r
b45b45b2 535 ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
536 UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
772db4bb 537\r
538 //\r
539 // Set the requests to the listening port, other packets to the connected port\r
540 //\r
16cd325f
ED
541 Buffer = NetbufGetByte (Instance->LastPacket, 0, NULL);\r
542 ASSERT (Buffer != NULL);\r
543 OpCode = NTOHS (*(UINT16 *) Buffer);\r
772db4bb 544\r
545 if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
546 (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
547 UdpPoint.RemotePort = Instance->ListeningPort;\r
548 } else {\r
549 UdpPoint.RemotePort = Instance->ConnectedPort;\r
550 }\r
551\r
552 NET_GET_REF (Instance->LastPacket);\r
553\r
554 Status = UdpIoSendDatagram (\r
555 Instance->UnicastPort,\r
556 Instance->LastPacket,\r
557 &UdpPoint,\r
b45b45b2 558 NULL,\r
772db4bb 559 Mtftp4OnPacketSent,\r
560 Instance\r
561 );\r
562\r
563 if (EFI_ERROR (Status)) {\r
564 NET_PUT_REF (Instance->LastPacket);\r
565 }\r
566\r
567 return Status;\r
568}\r
569\r
570\r
571/**\r
572 The timer ticking function for the Mtftp service instance.\r
573\r
574 @param Event The ticking event\r
575 @param Context The Mtftp service instance\r
576\r
772db4bb 577**/\r
578VOID\r
579EFIAPI\r
580Mtftp4OnTimerTick (\r
581 IN EFI_EVENT Event,\r
582 IN VOID *Context\r
583 )\r
584{\r
585 MTFTP4_SERVICE *MtftpSb;\r
e48e37fc 586 LIST_ENTRY *Entry;\r
587 LIST_ENTRY *Next;\r
772db4bb 588 MTFTP4_PROTOCOL *Instance;\r
589 EFI_MTFTP4_TOKEN *Token;\r
590\r
591 MtftpSb = (MTFTP4_SERVICE *) Context;\r
592\r
593 //\r
594 // Iterate through all the children of the Mtftp service instance. Time\r
595 // out the packet. If maximum retries reached, clean the session up.\r
596 //\r
597 NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {\r
598 Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);\r
599\r
600 if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {\r
601 continue;\r
602 }\r
603\r
604 //\r
605 // Call the user's time out handler\r
606 //\r
607 Token = Instance->Token;\r
608\r
609 if ((Token->TimeoutCallback != NULL) &&\r
610 EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {\r
611\r
612 Mtftp4SendError (\r
613 Instance,\r
614 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
67a58d0f 615 (UINT8 *) "User aborted the transfer in time out"\r
772db4bb 616 );\r
617\r
618 Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
619 continue;\r
620 }\r
621\r
622 //\r
623 // Retransmit the packet if haven't reach the maxmium retry count,\r
624 // otherwise exit the transfer.\r
625 //\r
626 if (++Instance->CurRetry < Instance->MaxRetry) {\r
627 Mtftp4Retransmit (Instance);\r
628 Mtftp4SetTimeout (Instance);\r
629 } else {\r
630 Mtftp4CleanOperation (Instance, EFI_TIMEOUT);\r
631 continue;\r
632 }\r
633 }\r
634}\r