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