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