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