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