]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Rrq.c
1 /** @file
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Mtftp4Rrq.c
15
16 Abstract:
17
18 Routines to process Rrq (download)
19
20
21 **/
22
23 #include "Mtftp4Impl.h"
24
25 VOID
26 Mtftp4RrqInput (
27 IN NET_BUF *UdpPacket,
28 IN UDP_POINTS *Points,
29 IN EFI_STATUS IoStatus,
30 IN VOID *Context
31 );
32
33
34 /**
35 Start the MTFTP session to download. It will first initialize some
36 of the internal states then build and send a RRQ reqeuest packet, at
37 last, it will start receive for the downloading.
38
39 @param Instance The Mtftp session
40 @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
41 or EFI_MTFTP4_OPCODE_DIR.
42
43 @retval EFI_SUCCESS The mtftp download session is started.
44 @retval Others Failed to start downloading.
45
46 **/
47 EFI_STATUS
48 Mtftp4RrqStart (
49 IN MTFTP4_PROTOCOL *Instance,
50 IN UINT16 Operation
51 )
52 {
53 EFI_STATUS Status;
54
55 //
56 // The valid block number range are [1, 0xffff]. For example:
57 // the client sends an RRQ request to the server, the server
58 // transfers the DATA1 block. If option negoitation is ongoing,
59 // the server will send back an OACK, then client will send ACK0.
60 //
61 Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);
62
63 if (EFI_ERROR (Status)) {
64 return Status;
65 }
66
67 Status = Mtftp4SendRequest (Instance);
68
69 if (EFI_ERROR (Status)) {
70 return Status;
71 }
72
73 return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
74 }
75
76
77 /**
78 Build and send a ACK packet for the download session.
79
80 @param Instance The Mtftp session
81 @param BlkNo The BlkNo to ack.
82
83 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
84 @retval EFI_SUCCESS The ACK has been sent
85 @retval Others Failed to send the ACK.
86
87 **/
88 EFI_STATUS
89 Mtftp4RrqSendAck (
90 IN MTFTP4_PROTOCOL *Instance,
91 IN UINT16 BlkNo
92 )
93 {
94 EFI_MTFTP4_PACKET *Ack;
95 NET_BUF *Packet;
96
97 Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));
98
99 if (Packet == NULL) {
100 return EFI_OUT_OF_RESOURCES;
101 }
102
103 Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (
104 Packet,
105 sizeof (EFI_MTFTP4_ACK_HEADER),
106 FALSE
107 );
108
109 Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
110 Ack->Ack.Block[0] = HTONS (BlkNo);
111
112 return Mtftp4SendPacket (Instance, Packet);
113 }
114
115
116 /**
117 Deliver the received data block to the user, which can be saved
118 in the user provide buffer or through the CheckPacket callback.
119
120 @param Instance The Mtftp session
121 @param Packet The received data packet
122 @param Len The packet length
123
124 @retval EFI_SUCCESS The data is saved successfully
125 @retval EFI_ABORTED The user tells to abort by return an error through
126 CheckPacket
127 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is
128 updated to the actual buffer size needed.
129
130 **/
131 EFI_STATUS
132 Mtftp4RrqSaveBlock (
133 IN MTFTP4_PROTOCOL *Instance,
134 IN EFI_MTFTP4_PACKET *Packet,
135 IN UINT32 Len
136 )
137 {
138 EFI_MTFTP4_TOKEN *Token;
139 EFI_STATUS Status;
140 UINT16 Block;
141 UINT64 Start;
142 UINT32 DataLen;
143
144 Token = Instance->Token;
145 Block = NTOHS (Packet->Data.Block);
146 DataLen = Len - MTFTP4_DATA_HEAD_LEN;
147
148 //
149 // This is the last block, save the block no
150 //
151 if (DataLen < Instance->BlkSize) {
152 Instance->LastBlock = Block;
153 Mtftp4SetLastBlockNum (&Instance->Blocks, Block);
154 }
155
156 //
157 // Remove this block number from the file hole. If Mtftp4RemoveBlockNum
158 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
159 //
160 Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block);
161
162 if (Status == EFI_NOT_FOUND) {
163 return EFI_SUCCESS;
164 } else if (EFI_ERROR (Status)) {
165 return Status;
166 }
167
168 if (Token->CheckPacket != NULL) {
169 Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);
170
171 if (EFI_ERROR (Status)) {
172 Mtftp4SendError (
173 Instance,
174 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
175 (UINT8 *) "User aborted download"
176 );
177
178 return EFI_ABORTED;
179 }
180 }
181
182 if (Token->Buffer != NULL) {
183 Start = MultU64x32 (Block - 1, Instance->BlkSize);
184
185 if (Start + DataLen <= Token->BufferSize) {
186 CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
187
188 //
189 // Update the file size when received the last block
190 //
191 if (Instance->LastBlock == Block) {
192 Token->BufferSize = Start + DataLen;
193 }
194
195 } else if (Instance->LastBlock != 0) {
196 //
197 // Don't save the data if the buffer is too small, return
198 // EFI_BUFFER_TOO_SMALL if received the last packet. This
199 // will give a accurate file length.
200 //
201 Token->BufferSize = Start + DataLen;
202
203 Mtftp4SendError (
204 Instance,
205 EFI_MTFTP4_ERRORCODE_DISK_FULL,
206 (UINT8 *) "User provided memory block is too small"
207 );
208
209 return EFI_BUFFER_TOO_SMALL;
210 }
211 }
212
213 return EFI_SUCCESS;
214 }
215
216
217 /**
218 Function to process the received data packets. It will save the block
219 then send back an ACK if it is active.
220
221 @param Instance The downloading MTFTP session
222 @param Packet The packet received
223 @param Len The length of the packet
224 @param Multicast Whether this packet is multicast or unicast
225 @param Completed Return whether the download has completed
226
227 @retval EFI_SUCCESS The data packet is successfully processed
228 @retval EFI_ABORTED The download is aborted by the user
229 @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
230
231 **/
232 EFI_STATUS
233 Mtftp4RrqHandleData (
234 IN MTFTP4_PROTOCOL *Instance,
235 IN EFI_MTFTP4_PACKET *Packet,
236 IN UINT32 Len,
237 IN BOOLEAN Multicast,
238 OUT BOOLEAN *Completed
239 )
240 {
241 EFI_STATUS Status;
242 UINT16 BlockNum;
243 INTN Expected;
244
245 *Completed = FALSE;
246 BlockNum = NTOHS (Packet->Data.Block);
247 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
248
249 ASSERT (Expected >= 0);
250
251 //
252 // If we are active and received an unexpected packet, retransmit
253 // the last ACK then restart receiving. If we are passive, save
254 // the block.
255 //
256 if (Instance->Master && (Expected != BlockNum)) {
257 Mtftp4Retransmit (Instance);
258 return EFI_SUCCESS;
259 }
260
261 Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);
262
263 if (EFI_ERROR (Status)) {
264 return Status;
265 }
266
267 //
268 // Reset the passive client's timer whenever it received a
269 // valid data packet.
270 //
271 if (!Instance->Master) {
272 Mtftp4SetTimeout (Instance);
273 }
274
275 //
276 // Check whether we have received all the blocks. Send the ACK if we
277 // are active (unicast client or master client for multicast download).
278 // If we have received all the blocks, send an ACK even if we are passive
279 // to tell the server that we are done.
280 //
281 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
282
283 if (Instance->Master || (Expected < 0)) {
284 if (Expected < 0) {
285 //
286 // If we are passive client, then the just received Block maybe
287 // isn't the last block. We need to send an ACK to the last block
288 // to inform the server that we are done. If we are active client,
289 // the Block == Instance->LastBlock.
290 //
291 BlockNum = Instance->LastBlock;
292 *Completed = TRUE;
293
294 } else {
295 BlockNum = (UINT16) (Expected - 1);
296 }
297
298 Mtftp4RrqSendAck (Instance, BlockNum);
299 }
300
301 return EFI_SUCCESS;
302 }
303
304
305 /**
306 Validate whether the options received in the server's OACK packet is valid.
307 The options are valid only if:
308 1. The server doesn't include options not requested by us
309 2. The server can only use smaller blksize than that is requested
310 3. The server can only use the same timeout as requested
311 4. The server doesn't change its multicast channel.
312
313 @param This The downloading Mtftp session
314 @param Reply The options in the OACK packet
315 @param Request The requested options
316
317 @return TRUE if the options in the OACK is OK, otherwise FALSE.
318
319 **/
320 BOOLEAN
321 Mtftp4RrqOackValid (
322 IN MTFTP4_PROTOCOL *This,
323 IN MTFTP4_OPTION *Reply,
324 IN MTFTP4_OPTION *Request
325 )
326 {
327
328 //
329 // It is invalid for server to return options we don't request
330 //
331 if ((Reply->Exist &~Request->Exist) != 0) {
332 return FALSE;
333 }
334
335 //
336 // Server can only specify a smaller block size to be used and
337 // return the timeout matches that requested.
338 //
339 if (((Reply->Exist & MTFTP4_BLKSIZE_EXIST) && (Reply->BlkSize > Request->BlkSize)) ||
340 ((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->Timeout))) {
341 return FALSE;
342 }
343
344 //
345 // The server can send ",,master" to client to change its master
346 // setting. But if it use the specific multicast channel, it can't
347 // change the setting.
348 //
349 if ((Reply->Exist & MTFTP4_MCAST_EXIST) && (This->McastIp != 0)) {
350 if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {
351 return FALSE;
352 }
353
354 if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {
355 return FALSE;
356 }
357 }
358
359 return TRUE;
360 }
361
362
363 /**
364 Configure a UDP IO port to receive the multicast.
365
366 @param McastIo The UDP IO port to configure
367 @param Context The opaque parameter to the function which is the
368 MTFTP session.
369
370 @retval EFI_SUCCESS The udp child is successfully configured.
371 @retval Others Failed to configure the UDP child.
372
373 **/
374 EFI_STATUS
375 Mtftp4RrqConfigMcastPort (
376 IN UDP_IO_PORT *McastIo,
377 IN VOID *Context
378 )
379 {
380 MTFTP4_PROTOCOL *Instance;
381 EFI_MTFTP4_CONFIG_DATA *Config;
382 EFI_UDP4_CONFIG_DATA UdpConfig;
383 EFI_IPv4_ADDRESS Group;
384 EFI_STATUS Status;
385 IP4_ADDR Ip;
386
387 Instance = (MTFTP4_PROTOCOL *) Context;
388 Config = &Instance->Config;
389
390 UdpConfig.AcceptBroadcast = FALSE;
391 UdpConfig.AcceptPromiscuous = FALSE;
392 UdpConfig.AcceptAnyPort = FALSE;
393 UdpConfig.AllowDuplicatePort = FALSE;
394 UdpConfig.TypeOfService = 0;
395 UdpConfig.TimeToLive = 64;
396 UdpConfig.DoNotFragment = FALSE;
397 UdpConfig.ReceiveTimeout = 0;
398 UdpConfig.TransmitTimeout = 0;
399 UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;
400 UdpConfig.StationAddress = Config->StationIp;
401 UdpConfig.SubnetMask = Config->SubnetMask;
402 UdpConfig.StationPort = Instance->McastPort;
403 UdpConfig.RemotePort = 0;
404
405 Ip = HTONL (Instance->ServerIp);
406 CopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
407
408 Status = McastIo->Udp->Configure (McastIo->Udp, &UdpConfig);
409
410 if (EFI_ERROR (Status)) {
411 return Status;
412 }
413
414 if (!Config->UseDefaultSetting && !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) {
415 //
416 // The station IP address is manually configured and the Gateway IP is not 0.
417 // Add the default route for this UDP instance.
418 //
419 Status = McastIo->Udp->Routes (McastIo->Udp, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &Config->GatewayIp);
420 if (EFI_ERROR (Status)) {
421 McastIo->Udp->Configure (McastIo->Udp, NULL);
422 return Status;
423 }
424 }
425
426 //
427 // join the multicast group
428 //
429 Ip = HTONL (Instance->McastIp);
430 CopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS));
431
432 return McastIo->Udp->Groups (McastIo->Udp, TRUE, &Group);
433 }
434
435
436 /**
437 Function to process the OACK. It will first validate the OACK
438 packet, then update the various negotiated parameters.
439
440 @param Instance The download MTFTP session
441 @param Packet The packet received
442 @param Len The packet length
443 @param Multicast Whether this packet is received as a multicast
444 @param Completed Returns whether the download has completed. NOT
445 used by this function.
446
447 @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
448 @retval EFI_TFTP_ERROR Some error happened during the process
449 @retval EFI_SUCCESS The OACK is successfully processed.
450
451 **/
452 EFI_STATUS
453 Mtftp4RrqHandleOack (
454 IN MTFTP4_PROTOCOL *Instance,
455 IN EFI_MTFTP4_PACKET *Packet,
456 IN UINT32 Len,
457 IN BOOLEAN Multicast,
458 OUT BOOLEAN *Completed
459 )
460 {
461 MTFTP4_OPTION Reply;
462 EFI_STATUS Status;
463 INTN Expected;
464
465 *Completed = FALSE;
466
467 //
468 // If already started the master download, don't change the
469 // setting. Master download always succeeds.
470 //
471 Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
472 ASSERT (Expected != -1);
473
474 if (Instance->Master && (Expected != 1)) {
475 return EFI_SUCCESS;
476 }
477
478 //
479 // Parse and validate the options from server
480 //
481 ZeroMem (&Reply, sizeof (MTFTP4_OPTION));
482
483 Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);
484
485 if (EFI_ERROR (Status) ||
486 !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {
487 //
488 // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
489 //
490 if (Status != EFI_OUT_OF_RESOURCES) {
491 Mtftp4SendError (
492 Instance,
493 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
494 (UINT8 *) "Mal-formated OACK packet"
495 );
496 }
497
498 return EFI_TFTP_ERROR;
499 }
500
501 if (Reply.Exist & MTFTP4_MCAST_EXIST) {
502
503 //
504 // Save the multicast info. Always update the Master, only update the
505 // multicast IP address, block size, timeoute at the first time. If IP
506 // address is updated, create a UDP child to receive the multicast.
507 //
508 Instance->Master = Reply.Master;
509
510 if (Instance->McastIp == 0) {
511 if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {
512 Mtftp4SendError (
513 Instance,
514 EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
515 (UINT8 *) "Illegal multicast setting"
516 );
517
518 return EFI_TFTP_ERROR;
519 }
520
521 //
522 // Create a UDP child then start receive the multicast from it.
523 //
524 Instance->McastIp = Reply.McastIp;
525 Instance->McastPort = Reply.McastPort;
526 Instance->McastUdpPort = UdpIoCreatePort (
527 Instance->Service->Controller,
528 Instance->Service->Image,
529 Mtftp4RrqConfigMcastPort,
530 Instance
531 );
532
533 if (Instance->McastUdpPort == NULL) {
534 return EFI_DEVICE_ERROR;
535 }
536
537 Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
538
539 if (EFI_ERROR (Status)) {
540 Mtftp4SendError (
541 Instance,
542 EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,
543 (UINT8 *) "Failed to create socket to receive multicast packet"
544 );
545
546 return Status;
547 }
548
549 //
550 // Update the parameters used.
551 //
552 if (Reply.BlkSize != 0) {
553 Instance->BlkSize = Reply.BlkSize;
554 }
555
556 if (Reply.Timeout != 0) {
557 Instance->Timeout = Reply.Timeout;
558 }
559 }
560
561 } else {
562 Instance->Master = TRUE;
563
564 if (Reply.BlkSize != 0) {
565 Instance->BlkSize = Reply.BlkSize;
566 }
567
568 if (Reply.Timeout != 0) {
569 Instance->Timeout = Reply.Timeout;
570 }
571 }
572
573 //
574 // Send an ACK to (Expected - 1) which is 0 for unicast download,
575 // or tell the server we want to receive the Expected block.
576 //
577 return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));
578 }
579
580
581 /**
582 The packet process callback for MTFTP download.
583
584 @param UdpPacket The packet received
585 @param Points The local/remote access point of the packet
586 @param IoStatus The status of the receiving
587 @param Context Opaque parameter, which is the MTFTP session
588
589 @return None
590
591 **/
592 VOID
593 Mtftp4RrqInput (
594 IN NET_BUF *UdpPacket,
595 IN UDP_POINTS *Points,
596 IN EFI_STATUS IoStatus,
597 IN VOID *Context
598 )
599 {
600 MTFTP4_PROTOCOL *Instance;
601 EFI_MTFTP4_PACKET *Packet;
602 BOOLEAN Completed;
603 BOOLEAN Multicast;
604 EFI_STATUS Status;
605 UINT16 Opcode;
606 UINT32 Len;
607
608 Instance = (MTFTP4_PROTOCOL *) Context;
609 NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
610
611 Status = EFI_SUCCESS;
612 Packet = NULL;
613 Completed = FALSE;
614 Multicast = FALSE;
615
616 if (EFI_ERROR (IoStatus)) {
617 Status = IoStatus;
618 goto ON_EXIT;
619 }
620
621 ASSERT (UdpPacket != NULL);
622
623 //
624 // Find the port this packet is from to restart receive correctly.
625 //
626 Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp);
627
628 if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
629 goto ON_EXIT;
630 }
631
632 //
633 // Client send initial request to server's listening port. Server
634 // will select a UDP port to communicate with the client. The server
635 // is required to use the same port as RemotePort to multicast the
636 // data.
637 //
638 if (Points->RemotePort != Instance->ConnectedPort) {
639 if (Instance->ConnectedPort != 0) {
640 goto ON_EXIT;
641 } else {
642 Instance->ConnectedPort = Points->RemotePort;
643 }
644 }
645
646 //
647 // Copy the MTFTP packet to a continuous buffer if it isn't already so.
648 //
649 Len = UdpPacket->TotalSize;
650
651 if (UdpPacket->BlockOpNum > 1) {
652 Packet = AllocatePool (Len);
653
654 if (Packet == NULL) {
655 Status = EFI_OUT_OF_RESOURCES;
656 goto ON_EXIT;
657 }
658
659 NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
660
661 } else {
662 Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
663 }
664
665 Opcode = NTOHS (Packet->OpCode);
666
667 //
668 // Call the user's CheckPacket if provided. Abort the transmission
669 // if CheckPacket returns an EFI_ERROR code.
670 //
671 if ((Instance->Token->CheckPacket != NULL) &&
672 ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
673
674 Status = Instance->Token->CheckPacket (
675 &Instance->Mtftp4,
676 Instance->Token,
677 (UINT16) Len,
678 Packet
679 );
680
681 if (EFI_ERROR (Status)) {
682 //
683 // Send an error message to the server to inform it
684 //
685 if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
686 Mtftp4SendError (
687 Instance,
688 EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
689 (UINT8 *) "User aborted the transfer"
690 );
691 }
692
693 Status = EFI_ABORTED;
694 goto ON_EXIT;
695 }
696 }
697
698 switch (Opcode) {
699 case EFI_MTFTP4_OPCODE_DATA:
700 if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||
701 (Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {
702 goto ON_EXIT;
703 }
704
705 Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);
706 break;
707
708 case EFI_MTFTP4_OPCODE_OACK:
709 if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {
710 goto ON_EXIT;
711 }
712
713 Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);
714 break;
715
716 case EFI_MTFTP4_OPCODE_ERROR:
717 Status = EFI_TFTP_ERROR;
718 break;
719 }
720
721 ON_EXIT:
722
723 //
724 // Free the resources, then if !EFI_ERROR (Status), restart the
725 // receive, otherwise end the session.
726 //
727 if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
728 gBS->FreePool (Packet);
729 }
730
731 if (UdpPacket != NULL) {
732 NetbufFree (UdpPacket);
733 }
734
735 if (!EFI_ERROR (Status) && !Completed) {
736 if (Multicast) {
737 Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
738 } else {
739 Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
740 }
741 }
742
743 if (EFI_ERROR (Status) || Completed) {
744 Mtftp4CleanOperation (Instance, Status);
745 }
746 }