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**/
30EFI_STATUS
31Mtftp6RrqSendAck (
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**/
84EFI_STATUS
85Mtftp6RrqSaveBlock (
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**/
213EFI_STATUS
214Mtftp6RrqHandleData (
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**/
314BOOLEAN
315Mtftp6RrqOackValid (
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**/
372EFI_STATUS
373EFIAPI
374Mtftp6RrqConfigMcastUdpIo (
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**/
443EFI_STATUS
444Mtftp6RrqHandleOack (
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**/
656VOID
657EFIAPI
658Mtftp6RrqInput (
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
839ON_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**/
888EFI_STATUS
889Mtftp6RrqStart (
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