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