1 /** @file
2   Mtftp6 Rrq process functions implementation.
3 
4   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5 
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.
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 #include "Mtftp6Impl.h"
17 
18 
19 /**
20   Build and send a ACK packet for download.
21 
22   @param[in]  Instance              The pointer to the Mtftp6 instance.
23   @param[in]  BlockNum              The block number to be acked.
24 
25   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for the packet.
26   @retval EFI_SUCCESS           The ACK has been sent.
27   @retval Others                Failed to send the ACK.
28 
29 **/
30 EFI_STATUS
Mtftp6RrqSendAck(IN MTFTP6_INSTANCE * Instance,IN UINT16 BlockNum)31 Mtftp6RrqSendAck (
32   IN MTFTP6_INSTANCE        *Instance,
33   IN UINT16                 BlockNum
34   )
35 {
36   EFI_MTFTP6_PACKET         *Ack;
37   NET_BUF                   *Packet;
38 
39   //
40   // Allocate net buffer to create ack packet.
41   //
42   Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));
43 
44   if (Packet == NULL) {
45     return EFI_OUT_OF_RESOURCES;
46   }
47 
48   Ack = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (
49                                 Packet,
50                                 sizeof (EFI_MTFTP6_ACK_HEADER),
51                                 FALSE
52                                 );
53   ASSERT (Ack != NULL);
54 
55   Ack->Ack.OpCode    = HTONS (EFI_MTFTP6_OPCODE_ACK);
56   Ack->Ack.Block[0]  = HTONS (BlockNum);
57 
58   //
59   // Reset current retry count of the instance.
60   //
61   Instance->CurRetry = 0;
62   Instance->LastPacket = Packet;
63 
64   return Mtftp6TransmitPacket (Instance, Packet);
65 }
66 
67 
68 /**
69   Deliver the received data block to the user, which can be saved
70   in the user provide buffer or through the CheckPacket callback.
71 
72   @param[in]  Instance              The pointer to the Mtftp6 instance.
73   @param[in]  Packet                The pointer to the received packet.
74   @param[in]  Len                   The packet length.
75   @param[out] UdpPacket             The net buf of the received packet.
76 
77   @retval EFI_SUCCESS           The data was saved successfully.
78   @retval EFI_ABORTED           The user tells to abort by return an error through
79                                 CheckPacket.
80   @retval EFI_BUFFER_TOO_SMALL  The user's buffer is too small, and buffer length is
81                                 updated to the actual buffer size needed.
82 
83 **/
84 EFI_STATUS
Mtftp6RrqSaveBlock(IN MTFTP6_INSTANCE * Instance,IN EFI_MTFTP6_PACKET * Packet,IN UINT32 Len,OUT NET_BUF ** UdpPacket)85 Mtftp6RrqSaveBlock (
86   IN  MTFTP6_INSTANCE       *Instance,
87   IN  EFI_MTFTP6_PACKET     *Packet,
88   IN  UINT32                Len,
89   OUT NET_BUF               **UdpPacket
90   )
91 {
92   EFI_MTFTP6_TOKEN          *Token;
93   EFI_STATUS                Status;
94   UINT16                    Block;
95   UINT64                    Start;
96   UINT32                    DataLen;
97   UINT64                    TotalBlock;
98   BOOLEAN                   Completed;
99 
100   Completed = FALSE;
101   Token     = Instance->Token;
102   Block     = NTOHS (Packet->Data.Block);
103   DataLen   = Len - MTFTP6_DATA_HEAD_LEN;
104 
105   //
106   // This is the last block, save the block num
107   //
108   if (DataLen < Instance->BlkSize) {
109     Completed = TRUE;
110     Instance->LastBlk = Block;
111     Mtftp6SetLastBlockNum (&Instance->BlkList, Block);
112   }
113 
114   //
115   // Remove this block number from the file hole. If Mtftp6RemoveBlockNum
116   // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
117   // Note that : For bigger files, allowing the block counter to roll over
118   // to accept transfers of unlimited size. So TotalBlock is memorised as
119   // continuous block counter.
120   //
121   Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &TotalBlock);
122 
123   if (Status == EFI_NOT_FOUND) {
124     return EFI_SUCCESS;
125   } else if (EFI_ERROR (Status)) {
126     return Status;
127   }
128 
129   if (Token->CheckPacket != NULL) {
130     //
131     // Callback to the check packet routine with the received packet.
132     //
133     Status = Token->CheckPacket (&Instance->Mtftp6, Token, (UINT16) Len, Packet);
134 
135     if (EFI_ERROR (Status)) {
136       //
137       // Free the received packet before send new packet in ReceiveNotify,
138       // since the Udp6Io might need to be reconfigured.
139       //
140       NetbufFree (*UdpPacket);
141       *UdpPacket = NULL;
142       //
143       // Send the Mtftp6 error message if user aborted the current session.
144       //
145       Mtftp6SendError (
146         Instance,
147         EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
148         (UINT8 *) "User aborted download"
149         );
150 
151       return EFI_ABORTED;
152     }
153   }
154 
155   if (Token->Buffer != NULL) {
156 
157     Start = MultU64x32 (TotalBlock - 1, Instance->BlkSize);
158     if (Start + DataLen <= Token->BufferSize) {
159       CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
160       //
161       // Update the file size when received the last block
162       //
163       if ((Instance->LastBlk == Block) && Completed) {
164         Token->BufferSize = Start + DataLen;
165       }
166     } else if (Instance->LastBlk != 0) {
167       //
168       // Don't save the data if the buffer is too small, return
169       // EFI_BUFFER_TOO_SMALL if received the last packet. This
170       // will give a accurate file length.
171       //
172       Token->BufferSize = Start + DataLen;
173 
174       //
175       // Free the received packet before send new packet in ReceiveNotify,
176       // since the udpio might need to be reconfigured.
177       //
178       NetbufFree (*UdpPacket);
179       *UdpPacket = NULL;
180       //
181       // Send the Mtftp6 error message if no enough buffer.
182       //
183       Mtftp6SendError (
184         Instance,
185         EFI_MTFTP6_ERRORCODE_DISK_FULL,
186         (UINT8 *) "User provided memory block is too small"
187         );
188 
189       return EFI_BUFFER_TOO_SMALL;
190     }
191   }
192 
193   return EFI_SUCCESS;
194 }
195 
196 
197 /**
198   Process the received data packets. It will save the block
199   then send back an ACK if it is active.
200 
201   @param[in]  Instance              The pointer to the Mtftp6 instance.
202   @param[in]  Packet                The pointer to the received packet.
203   @param[in]  Len                   The length of the packet.
204   @param[out] UdpPacket             The net buf of received packet.
205   @param[out] IsCompleted           If TRUE, the download has been completed.
206                                     Otherwise, the download has not been completed.
207 
208   @retval EFI_SUCCESS           The data packet was successfully processed.
209   @retval EFI_ABORTED           The download was aborted by the user.
210   @retval EFI_BUFFER_TOO_SMALL  The user-provided buffer is too small.
211 
212 **/
213 EFI_STATUS
Mtftp6RrqHandleData(IN MTFTP6_INSTANCE * Instance,IN EFI_MTFTP6_PACKET * Packet,IN UINT32 Len,OUT NET_BUF ** UdpPacket,OUT BOOLEAN * IsCompleted)214 Mtftp6RrqHandleData (
215   IN  MTFTP6_INSTANCE       *Instance,
216   IN  EFI_MTFTP6_PACKET     *Packet,
217   IN  UINT32                Len,
218   OUT NET_BUF               **UdpPacket,
219   OUT BOOLEAN               *IsCompleted
220   )
221 {
222   EFI_STATUS                Status;
223   UINT16                    BlockNum;
224   INTN                      Expected;
225 
226   *IsCompleted = FALSE;
227   BlockNum     = NTOHS (Packet->Data.Block);
228   Expected     = Mtftp6GetNextBlockNum (&Instance->BlkList);
229 
230   ASSERT (Expected >= 0);
231 
232   //
233   // If we are active and received an unexpected packet, retransmit
234   // the last ACK then restart receiving. If we are passive, save
235   // the block.
236   //
237   if (Instance->IsMaster && (Expected != BlockNum)) {
238     //
239     // Free the received packet before send new packet in ReceiveNotify,
240     // since the udpio might need to be reconfigured.
241     //
242     NetbufFree (*UdpPacket);
243     *UdpPacket = NULL;
244 
245     Mtftp6TransmitPacket (Instance, Instance->LastPacket);
246     return EFI_SUCCESS;
247   }
248 
249   Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);
250 
251   if (EFI_ERROR (Status)) {
252     return Status;
253   }
254 
255   //
256   // Reset the passive client's timer whenever it received a valid data packet.
257   //
258   if (!Instance->IsMaster) {
259     Instance->PacketToLive = Instance->Timeout * 2;
260   }
261 
262   //
263   // Check whether we have received all the blocks. Send the ACK if we
264   // are active (unicast client or master client for multicast download).
265   // If we have received all the blocks, send an ACK even if we are passive
266   // to tell the server that we are done.
267   //
268   Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
269 
270   if (Instance->IsMaster || Expected < 0) {
271     if (Expected < 0) {
272       //
273       // If we are passive client, then the just received Block maybe
274       // isn't the last block. We need to send an ACK to the last block
275       // to inform the server that we are done. If we are active client,
276       // the Block == Instance->LastBlock.
277       //
278       BlockNum     = Instance->LastBlk;
279       *IsCompleted = TRUE;
280 
281     } else {
282       BlockNum     = (UINT16) (Expected - 1);
283     }
284     //
285     // Free the received packet before send new packet in ReceiveNotify,
286     // since the udpio might need to be reconfigured.
287     //
288     NetbufFree (*UdpPacket);
289     *UdpPacket = NULL;
290 
291     Mtftp6RrqSendAck (Instance, BlockNum);
292   }
293 
294   return EFI_SUCCESS;
295 }
296 
297 
298 /**
299   Validate whether the options received in the server's OACK packet is valid.
300   The options are valid only if:
301   1. The server doesn't include options not requested by us.
302   2. The server can only use smaller blksize than that is requested.
303   3. The server can only use the same timeout as requested.
304   4. The server doesn't change its multicast channel.
305 
306   @param[in]  Instance              The pointer to the Mtftp6 instance.
307   @param[in]  ReplyInfo             The pointer to options information in reply packet.
308   @param[in]  RequestInfo           The pointer to requested options info.
309 
310   @retval     TRUE                  If the option in the OACK is valid.
311   @retval     FALSE                 If the option is invalid.
312 
313 **/
314 BOOLEAN
Mtftp6RrqOackValid(IN MTFTP6_INSTANCE * Instance,IN MTFTP6_EXT_OPTION_INFO * ReplyInfo,IN MTFTP6_EXT_OPTION_INFO * RequestInfo)315 Mtftp6RrqOackValid (
316   IN MTFTP6_INSTANCE           *Instance,
317   IN MTFTP6_EXT_OPTION_INFO    *ReplyInfo,
318   IN MTFTP6_EXT_OPTION_INFO    *RequestInfo
319   )
320 {
321   //
322   // It is invalid for server to return options we don't request
323   //
324   if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
325     return FALSE;
326   }
327 
328   //
329   // Server can only specify a smaller block size to be used and
330   // return the timeout matches that requested.
331   //
332   if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
333       (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
334       ) {
335     return FALSE;
336   }
337 
338   //
339   // The server can send ",,master" to client to change its master
340   // setting. But if it use the specific multicast channel, it can't
341   // change the setting.
342   //
343   if (((ReplyInfo->BitMap & MTFTP6_OPT_MCAST_BIT) != 0) && !NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
344 
345     if (!NetIp6IsUnspecifiedAddr (&ReplyInfo->McastIp) && CompareMem (
346                                                             &ReplyInfo->McastIp,
347                                                             &Instance->McastIp,
348                                                             sizeof (EFI_IPv6_ADDRESS)
349                                                             ) != 0) {
350       return FALSE;
351     }
352 
353     if ((ReplyInfo->McastPort != 0) && (ReplyInfo->McastPort != Instance->McastPort)) {
354       return FALSE;
355     }
356   }
357 
358   return TRUE;
359 }
360 
361 
362 /**
363   Configure Udp6Io to receive a packet from a multicast address.
364 
365   @param[in]  McastIo               The pointer to the mcast Udp6Io.
366   @param[in]  Context               The pointer to the context.
367 
368   @retval EFI_SUCCESS           The mcast Udp6Io was successfully configured.
369   @retval Others                Failed to configure the Udp6Io.
370 
371 **/
372 EFI_STATUS
373 EFIAPI
Mtftp6RrqConfigMcastUdpIo(IN UDP_IO * McastIo,IN VOID * Context)374 Mtftp6RrqConfigMcastUdpIo (
375   IN UDP_IO                 *McastIo,
376   IN VOID                   *Context
377   )
378 {
379   EFI_STATUS                Status;
380   EFI_UDP6_PROTOCOL         *Udp6;
381   EFI_UDP6_CONFIG_DATA      *Udp6Cfg;
382   EFI_IPv6_ADDRESS          Group;
383   MTFTP6_INSTANCE           *Instance;
384 
385   Udp6     = McastIo->Protocol.Udp6;
386   Udp6Cfg  = &(McastIo->Config.Udp6);
387   Instance = (MTFTP6_INSTANCE *) Context;
388 
389   //
390   // Set the configure data for the mcast Udp6Io.
391   //
392   ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
393 
394   Udp6Cfg->AcceptPromiscuous  = FALSE;
395   Udp6Cfg->AcceptAnyPort      = FALSE;
396   Udp6Cfg->AllowDuplicatePort = FALSE;
397   Udp6Cfg->TrafficClass       = 0;
398   Udp6Cfg->HopLimit           = 128;
399   Udp6Cfg->ReceiveTimeout     = 0;
400   Udp6Cfg->TransmitTimeout    = 0;
401   Udp6Cfg->StationPort        = Instance->McastPort;
402   Udp6Cfg->RemotePort         = 0;
403 
404   CopyMem (
405     &Udp6Cfg->RemoteAddress,
406     &Instance->ServerIp,
407     sizeof (EFI_IPv6_ADDRESS)
408     );
409 
410   //
411   // Configure the mcast Udp6Io.
412   //
413   Status = Udp6->Configure (Udp6, Udp6Cfg);
414 
415   if (EFI_ERROR (Status)) {
416     return Status;
417   }
418 
419   //
420   // Join the multicast group
421   //
422   CopyMem (&Group, &Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
423 
424   return Udp6->Groups (Udp6, TRUE, &Group);
425 }
426 
427 
428 /**
429   Process the OACK packet for Rrq.
430 
431   @param[in]  Instance              The pointer to the Mtftp6 instance.
432   @param[in]  Packet                The pointer to the received packet.
433   @param[in]  Len                   The length of the packet.
434   @param[out] UdpPacket             The net buf of received packet.
435   @param[out] IsCompleted           If TRUE, the download has been completed.
436                                     Otherwise, the download has not been completed.
437 
438   @retval EFI_DEVICE_ERROR      Failed to create/start a multicast Udp6 child.
439   @retval EFI_TFTP_ERROR        An error happened during the process.
440   @retval EFI_SUCCESS           The OACK packet successfully processed.
441 
442 **/
443 EFI_STATUS
Mtftp6RrqHandleOack(IN MTFTP6_INSTANCE * Instance,IN EFI_MTFTP6_PACKET * Packet,IN UINT32 Len,OUT NET_BUF ** UdpPacket,OUT BOOLEAN * IsCompleted)444 Mtftp6RrqHandleOack (
445   IN  MTFTP6_INSTANCE       *Instance,
446   IN  EFI_MTFTP6_PACKET     *Packet,
447   IN  UINT32                Len,
448   OUT NET_BUF               **UdpPacket,
449   OUT BOOLEAN               *IsCompleted
450   )
451 {
452   EFI_MTFTP6_OPTION         *Options;
453   UINT32                    Count;
454   MTFTP6_EXT_OPTION_INFO    ExtInfo;
455   EFI_STATUS                Status;
456   INTN                      Expected;
457   EFI_UDP6_PROTOCOL         *Udp6;
458 
459   *IsCompleted = FALSE;
460   Options = NULL;
461 
462   //
463   // If already started the master download, don't change the
464   // setting. Master download always succeeds.
465   //
466   Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
467   ASSERT (Expected != -1);
468 
469   if (Instance->IsMaster && Expected != 1) {
470     return EFI_SUCCESS;
471   }
472 
473   ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
474 
475   //
476   // Parse the options in the packet.
477   //
478   Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
479 
480   if (EFI_ERROR (Status)) {
481     return Status;
482   }
483   ASSERT (Options != NULL);
484 
485   //
486   // Parse the extensive options in the packet.
487   //
488   Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
489 
490   if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {
491     //
492     // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
493     //
494     if (Status != EFI_OUT_OF_RESOURCES) {
495       //
496       // Free the received packet before send new packet in ReceiveNotify,
497       // since the udpio might need to be reconfigured.
498       //
499       NetbufFree (*UdpPacket);
500       *UdpPacket = NULL;
501       //
502       // Send the Mtftp6 error message if invalid packet.
503       //
504       Mtftp6SendError (
505         Instance,
506         EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
507         (UINT8 *) "Mal-formated OACK packet"
508         );
509     }
510 
511     return EFI_TFTP_ERROR;
512   }
513 
514   if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {
515 
516     //
517     // Save the multicast info. Always update the Master, only update the
518     // multicast IP address, block size, timeoute at the first time. If IP
519     // address is updated, create a UDP child to receive the multicast.
520     //
521     Instance->IsMaster = ExtInfo.IsMaster;
522 
523     if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
524       if (NetIp6IsUnspecifiedAddr (&ExtInfo.McastIp) || ExtInfo.McastPort == 0) {
525         //
526         // Free the received packet before send new packet in ReceiveNotify,
527         // since the udpio might need to be reconfigured.
528         //
529         NetbufFree (*UdpPacket);
530         *UdpPacket = NULL;
531         //
532         // Send the Mtftp6 error message if invalid multi-cast setting.
533         //
534         Mtftp6SendError (
535           Instance,
536           EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
537           (UINT8 *) "Illegal multicast setting"
538           );
539 
540         return EFI_TFTP_ERROR;
541       }
542 
543       //
544       // Create a UDP child then start receive the multicast from it.
545       //
546       CopyMem (
547         &Instance->McastIp,
548         &ExtInfo.McastIp,
549         sizeof (EFI_IP_ADDRESS)
550         );
551 
552       Instance->McastPort  = ExtInfo.McastPort;
553       if (Instance->McastUdpIo == NULL) {
554         Instance->McastUdpIo = UdpIoCreateIo (
555                                  Instance->Service->Controller,
556                                  Instance->Service->Image,
557                                  Mtftp6RrqConfigMcastUdpIo,
558                                  UDP_IO_UDP6_VERSION,
559                                  Instance
560                                  );
561         if (Instance->McastUdpIo != NULL) {
562           Status = gBS->OpenProtocol (
563                           Instance->McastUdpIo->UdpHandle,
564                           &gEfiUdp6ProtocolGuid,
565                           (VOID **) &Udp6,
566                           Instance->Service->Image,
567                           Instance->Handle,
568                           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
569                           );
570           if (EFI_ERROR (Status)) {
571             UdpIoFreeIo (Instance->McastUdpIo);
572             Instance->McastUdpIo = NULL;
573             return EFI_DEVICE_ERROR;
574           }
575         }
576       }
577 
578       if (Instance->McastUdpIo == NULL) {
579         return EFI_DEVICE_ERROR;
580       }
581 
582       Status = UdpIoRecvDatagram (
583                  Instance->McastUdpIo,
584                  Mtftp6RrqInput,
585                  Instance,
586                  0
587                  );
588 
589       if (EFI_ERROR (Status)) {
590         //
591         // Free the received packet before send new packet in ReceiveNotify,
592         // since the udpio might need to be reconfigured.
593         //
594         NetbufFree (*UdpPacket);
595         *UdpPacket = NULL;
596         //
597         // Send the Mtftp6 error message if failed to create Udp6Io to receive.
598         //
599         Mtftp6SendError (
600           Instance,
601           EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION,
602           (UINT8 *) "Failed to create socket to receive multicast packet"
603           );
604 
605         return Status;
606       }
607 
608       //
609       // Update the parameters used.
610       //
611       if (ExtInfo.BlkSize != 0) {
612         Instance->BlkSize = ExtInfo.BlkSize;
613       }
614 
615       if (ExtInfo.Timeout != 0) {
616         Instance->Timeout = ExtInfo.Timeout;
617       }
618     }
619 
620   } else {
621 
622     Instance->IsMaster = TRUE;
623 
624     if (ExtInfo.BlkSize != 0) {
625       Instance->BlkSize = ExtInfo.BlkSize;
626     }
627 
628     if (ExtInfo.Timeout != 0) {
629       Instance->Timeout = ExtInfo.Timeout;
630     }
631   }
632 
633   //
634   // Free the received packet before send new packet in ReceiveNotify,
635   // since the udpio might need to be reconfigured.
636   //
637   NetbufFree (*UdpPacket);
638   *UdpPacket = NULL;
639   //
640   // Send an ACK to (Expected - 1) which is 0 for unicast download,
641   // or tell the server we want to receive the Expected block.
642   //
643   return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1));
644 }
645 
646 
647 /**
648   The packet process callback for Mtftp6 download.
649 
650   @param[in]  UdpPacket             The pointer to the packet received.
651   @param[in]  UdpEpt                The pointer to the Udp6 access point.
652   @param[in]  IoStatus              The status from Udp6 instance.
653   @param[in]  Context               The pointer to the context.
654 
655 **/
656 VOID
657 EFIAPI
Mtftp6RrqInput(IN NET_BUF * UdpPacket,IN UDP_END_POINT * UdpEpt,IN EFI_STATUS IoStatus,IN VOID * Context)658 Mtftp6RrqInput (
659   IN NET_BUF                *UdpPacket,
660   IN UDP_END_POINT          *UdpEpt,
661   IN EFI_STATUS             IoStatus,
662   IN VOID                   *Context
663   )
664 {
665   MTFTP6_INSTANCE           *Instance;
666   EFI_MTFTP6_PACKET         *Packet;
667   BOOLEAN                   IsCompleted;
668   BOOLEAN                   IsMcast;
669   EFI_STATUS                Status;
670   UINT16                    Opcode;
671   UINT32                    TotalNum;
672   UINT32                    Len;
673 
674   Instance = (MTFTP6_INSTANCE *) Context;
675 
676   NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
677 
678   Status      = EFI_SUCCESS;
679   Packet      = NULL;
680   IsCompleted = FALSE;
681   IsMcast     = FALSE;
682   TotalNum    = 0;
683 
684   //
685   // Return error status if Udp6 instance failed to receive.
686   //
687   if (EFI_ERROR (IoStatus)) {
688     Status = IoStatus;
689     goto ON_EXIT;
690   }
691 
692   ASSERT (UdpPacket != NULL);
693 
694   if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
695     goto ON_EXIT;
696   }
697 
698   //
699   // Find the port this packet is from to restart receive correctly.
700   //
701   if (CompareMem (
702         Ip6Swap128 (&UdpEpt->LocalAddr.v6),
703         &Instance->McastIp,
704         sizeof (EFI_IPv6_ADDRESS)
705         ) == 0) {
706     IsMcast = TRUE;
707   } else {
708     IsMcast = FALSE;
709   }
710 
711   //
712   // Client send initial request to server's listening port. Server
713   // will select a UDP port to communicate with the client. The server
714   // is required to use the same port as RemotePort to multicast the
715   // data.
716   //
717   if (UdpEpt->RemotePort != Instance->ServerDataPort) {
718     if (Instance->ServerDataPort != 0) {
719       goto ON_EXIT;
720     } else {
721       //
722       // For the subsequent exchange of requests, reconfigure the udpio as
723       // (serverip, serverport, localip, localport).
724       // Ususally, the client set serverport as 0 to receive and reset it
725       // once the first packet arrives to send ack.
726       //
727       Instance->ServerDataPort = UdpEpt->RemotePort;
728     }
729   }
730 
731   //
732   // Copy the MTFTP packet to a continuous buffer if it isn't already so.
733   //
734   Len      = UdpPacket->TotalSize;
735   TotalNum = UdpPacket->BlockOpNum;
736 
737   if (TotalNum > 1) {
738     Packet = AllocateZeroPool (Len);
739 
740     if (Packet == NULL) {
741       Status = EFI_OUT_OF_RESOURCES;
742       goto ON_EXIT;
743     }
744 
745     NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
746 
747   } else {
748     Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
749     ASSERT (Packet != NULL);
750   }
751 
752   Opcode = NTOHS (Packet->OpCode);
753 
754   //
755   // Callback to the user's CheckPacket if provided. Abort the transmission
756   // if CheckPacket returns an EFI_ERROR code.
757   //
758   if ((Instance->Token->CheckPacket != NULL) &&
759       (Opcode == EFI_MTFTP6_OPCODE_OACK || Opcode == EFI_MTFTP6_OPCODE_ERROR)
760       ) {
761 
762     Status = Instance->Token->CheckPacket (
763                                 &Instance->Mtftp6,
764                                 Instance->Token,
765                                 (UINT16) Len,
766                                 Packet
767                                 );
768 
769     if (EFI_ERROR (Status)) {
770       //
771       // Send an error message to the server to inform it
772       //
773       if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
774         //
775         // Free the received packet before send new packet in ReceiveNotify,
776         // since the udpio might need to be reconfigured.
777         //
778         NetbufFree (UdpPacket);
779         UdpPacket = NULL;
780         //
781         // Send the Mtftp6 error message if user aborted the current session.
782         //
783         Mtftp6SendError (
784           Instance,
785           EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
786           (UINT8 *) "User aborted the transfer"
787           );
788       }
789 
790       Status = EFI_ABORTED;
791       goto ON_EXIT;
792     }
793   }
794 
795   //
796   // Switch the process routines by the operation code.
797   //
798   switch (Opcode) {
799   case EFI_MTFTP6_OPCODE_DATA:
800     if ((Len > (UINT32) (MTFTP6_DATA_HEAD_LEN + Instance->BlkSize)) || (Len < (UINT32) MTFTP6_DATA_HEAD_LEN)) {
801       goto ON_EXIT;
802     }
803     //
804     // Handle the data packet of Rrq.
805     //
806     Status = Mtftp6RrqHandleData (
807                Instance,
808                Packet,
809                Len,
810                &UdpPacket,
811                &IsCompleted
812                );
813     break;
814 
815   case EFI_MTFTP6_OPCODE_OACK:
816     if (IsMcast || Len <= MTFTP6_OPCODE_LEN) {
817       goto ON_EXIT;
818     }
819     //
820     // Handle the Oack packet of Rrq.
821     //
822     Status = Mtftp6RrqHandleOack (
823                Instance,
824                Packet,
825                Len,
826                &UdpPacket,
827                &IsCompleted
828                );
829     break;
830 
831   default:
832     //
833     // Drop and return eror if received error message.
834     //
835     Status = EFI_TFTP_ERROR;
836     break;
837   }
838 
839 ON_EXIT:
840   //
841   // Free the resources, then if !EFI_ERROR (Status), restart the
842   // receive, otherwise end the session.
843   //
844   if (Packet != NULL && TotalNum > 1) {
845     FreePool (Packet);
846   }
847   if (UdpPacket != NULL) {
848     NetbufFree (UdpPacket);
849   }
850   if (!EFI_ERROR (Status) && !IsCompleted) {
851     if (IsMcast) {
852       Status = UdpIoRecvDatagram (
853                  Instance->McastUdpIo,
854                  Mtftp6RrqInput,
855                  Instance,
856                  0
857                  );
858     } else {
859       Status = UdpIoRecvDatagram (
860                  Instance->UdpIo,
861                  Mtftp6RrqInput,
862                  Instance,
863                  0
864                  );
865     }
866   }
867   //
868   // Clean up the current session if failed to continue.
869   //
870   if (EFI_ERROR (Status) || IsCompleted) {
871     Mtftp6OperationClean (Instance, Status);
872   }
873 }
874 
875 
876 /**
877   Start the Mtftp6 instance to download. It first initializes some
878   of the internal states, then builds and sends an RRQ reqeuest packet.
879   Finally, it starts receive for the downloading.
880 
881   @param[in]  Instance              The pointer to the Mtftp6 instance.
882   @param[in]  Operation             The operation code of current packet.
883 
884   @retval EFI_SUCCESS           The Mtftp6 is started to download.
885   @retval Others                Failed to start to download.
886 
887 **/
888 EFI_STATUS
Mtftp6RrqStart(IN MTFTP6_INSTANCE * Instance,IN UINT16 Operation)889 Mtftp6RrqStart (
890   IN MTFTP6_INSTANCE        *Instance,
891   IN UINT16                 Operation
892   )
893 {
894   EFI_STATUS                Status;
895 
896   //
897   // The valid block number range are [1, 0xffff]. For example:
898   // the client sends an RRQ request to the server, the server
899   // transfers the DATA1 block. If option negoitation is ongoing,
900   // the server will send back an OACK, then client will send ACK0.
901   //
902   Status = Mtftp6InitBlockRange (&Instance->BlkList, 1, 0xffff);
903 
904   if (EFI_ERROR (Status)) {
905     return Status;
906   }
907 
908   Status = Mtftp6SendRequest (Instance, Operation);
909 
910   if (EFI_ERROR (Status)) {
911     return Status;
912   }
913 
914   return UdpIoRecvDatagram (
915            Instance->UdpIo,
916            Mtftp6RrqInput,
917            Instance,
918            0
919            );
920 }
921 
922