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