]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
NetworkPkg: Replace BSD License with BSD+Patent License
[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 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "Mtftp6Impl.h"
11
12
13 /**
14 Build and send a ACK packet for download.
15
16 @param[in] Instance The pointer to the Mtftp6 instance.
17 @param[in] BlockNum The block number to be acked.
18
19 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
20 @retval EFI_SUCCESS The ACK has been sent.
21 @retval Others Failed to send the ACK.
22
23 **/
24 EFI_STATUS
25 Mtftp6RrqSendAck (
26 IN MTFTP6_INSTANCE *Instance,
27 IN UINT16 BlockNum
28 )
29 {
30 EFI_MTFTP6_PACKET *Ack;
31 NET_BUF *Packet;
32 EFI_STATUS Status;
33
34 Status = EFI_SUCCESS;
35
36 //
37 // Allocate net buffer to create ack packet.
38 //
39 Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));
40
41 if (Packet == NULL) {
42 return EFI_OUT_OF_RESOURCES;
43 }
44
45 Ack = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (
46 Packet,
47 sizeof (EFI_MTFTP6_ACK_HEADER),
48 FALSE
49 );
50 ASSERT (Ack != NULL);
51
52 Ack->Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);
53 Ack->Ack.Block[0] = HTONS (BlockNum);
54
55 //
56 // Reset current retry count of the instance.
57 //
58 Instance->CurRetry = 0;
59 Instance->LastPacket = Packet;
60
61 Status = Mtftp6TransmitPacket (Instance, Packet);
62 if (!EFI_ERROR (Status)) {
63 Instance->AckedBlock = Instance->TotalBlock;
64 }
65
66 return Status;
67 }
68
69
70 /**
71 Deliver the received data block to the user, which can be saved
72 in the user provide buffer or through the CheckPacket callback.
73
74 @param[in] Instance The pointer to the Mtftp6 instance.
75 @param[in] Packet The pointer to the received packet.
76 @param[in] Len The packet length.
77 @param[out] UdpPacket The net buf of the received packet.
78
79 @retval EFI_SUCCESS The data was saved successfully.
80 @retval EFI_ABORTED The user tells to abort by return an error through
81 CheckPacket.
82 @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small, and buffer length is
83 updated to the actual buffer size needed.
84
85 **/
86 EFI_STATUS
87 Mtftp6RrqSaveBlock (
88 IN MTFTP6_INSTANCE *Instance,
89 IN EFI_MTFTP6_PACKET *Packet,
90 IN UINT32 Len,
91 OUT NET_BUF **UdpPacket
92 )
93 {
94 EFI_MTFTP6_TOKEN *Token;
95 EFI_STATUS Status;
96 UINT16 Block;
97 UINT64 Start;
98 UINT32 DataLen;
99 UINT64 BlockCounter;
100 BOOLEAN Completed;
101
102 Completed = FALSE;
103 Token = Instance->Token;
104 Block = NTOHS (Packet->Data.Block);
105 DataLen = Len - MTFTP6_DATA_HEAD_LEN;
106
107 //
108 // This is the last block, save the block num
109 //
110 if (DataLen < Instance->BlkSize) {
111 Completed = TRUE;
112 Instance->LastBlk = Block;
113 Mtftp6SetLastBlockNum (&Instance->BlkList, Block);
114 }
115
116 //
117 // Remove this block number from the file hole. If Mtftp6RemoveBlockNum
118 // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
119 // Note that : For bigger files, allowing the block counter to roll over
120 // to accept transfers of unlimited size. So BlockCounter is memorised as
121 // continuous block counter.
122 //
123 Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &BlockCounter);
124
125 if (Status == EFI_NOT_FOUND) {
126 return EFI_SUCCESS;
127 } else if (EFI_ERROR (Status)) {
128 return Status;
129 }
130
131 if (Token->CheckPacket != NULL) {
132 //
133 // Callback to the check packet routine with the received packet.
134 //
135 Status = Token->CheckPacket (&Instance->Mtftp6, Token, (UINT16) Len, Packet);
136
137 if (EFI_ERROR (Status)) {
138 //
139 // Free the received packet before send new packet in ReceiveNotify,
140 // since the Udp6Io might need to be reconfigured.
141 //
142 NetbufFree (*UdpPacket);
143 *UdpPacket = NULL;
144 //
145 // Send the Mtftp6 error message if user aborted the current session.
146 //
147 Mtftp6SendError (
148 Instance,
149 EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
150 (UINT8 *) "User aborted download"
151 );
152
153 return EFI_ABORTED;
154 }
155 }
156
157 if (Token->Buffer != NULL) {
158
159 Start = MultU64x32 (BlockCounter - 1, Instance->BlkSize);
160 if (Start + DataLen <= Token->BufferSize) {
161 CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
162 //
163 // Update the file size when received the last block
164 //
165 if ((Instance->LastBlk == Block) && Completed) {
166 Token->BufferSize = Start + DataLen;
167 }
168 } else if (Instance->LastBlk != 0) {
169 //
170 // Don't save the data if the buffer is too small, return
171 // EFI_BUFFER_TOO_SMALL if received the last packet. This
172 // will give a accurate file length.
173 //
174 Token->BufferSize = Start + DataLen;
175
176 //
177 // Free the received packet before send new packet in ReceiveNotify,
178 // since the udpio might need to be reconfigured.
179 //
180 NetbufFree (*UdpPacket);
181 *UdpPacket = NULL;
182 //
183 // Send the Mtftp6 error message if no enough buffer.
184 //
185 Mtftp6SendError (
186 Instance,
187 EFI_MTFTP6_ERRORCODE_DISK_FULL,
188 (UINT8 *) "User provided memory block is too small"
189 );
190
191 return EFI_BUFFER_TOO_SMALL;
192 }
193 }
194
195 return EFI_SUCCESS;
196 }
197
198
199 /**
200 Process the received data packets. It will save the block
201 then send back an ACK if it is active.
202
203 @param[in] Instance The pointer to the Mtftp6 instance.
204 @param[in] Packet The pointer to the received packet.
205 @param[in] Len The length of the packet.
206 @param[out] UdpPacket The net buf of received packet.
207 @param[out] IsCompleted If TRUE, the download has been completed.
208 Otherwise, the download has not been completed.
209
210 @retval EFI_SUCCESS The data packet was successfully processed.
211 @retval EFI_ABORTED The download was aborted by the user.
212 @retval EFI_BUFFER_TOO_SMALL The user-provided buffer is too small.
213
214 **/
215 EFI_STATUS
216 Mtftp6RrqHandleData (
217 IN MTFTP6_INSTANCE *Instance,
218 IN EFI_MTFTP6_PACKET *Packet,
219 IN UINT32 Len,
220 OUT NET_BUF **UdpPacket,
221 OUT BOOLEAN *IsCompleted
222 )
223 {
224 EFI_STATUS Status;
225 UINT16 BlockNum;
226 INTN Expected;
227
228 *IsCompleted = FALSE;
229 Status = EFI_SUCCESS;
230 BlockNum = NTOHS (Packet->Data.Block);
231 Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
232
233 ASSERT (Expected >= 0);
234
235 //
236 // If we are active (Master) and received an unexpected packet, transmit
237 // the ACK for the block we received, then restart receiving the
238 // expected one. If we are passive (Slave), save the block.
239 //
240 if (Instance->IsMaster && (Expected != BlockNum)) {
241 //
242 // Free the received packet before send new packet in ReceiveNotify,
243 // since the udpio might need to be reconfigured.
244 //
245 NetbufFree (*UdpPacket);
246 *UdpPacket = NULL;
247
248 //
249 // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).
250 //
251 return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1));
252 }
253
254 Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);
255
256 if (EFI_ERROR (Status)) {
257 return Status;
258 }
259
260 //
261 // Record the total received and saved block number.
262 //
263 Instance->TotalBlock ++;
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