]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_mtftp.c
1. Add EFI LOADED IMAGE DEVICE PATH Protocol in LoadImage() service, per UEFI 2.1b.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_bc_mtftp.c
1 /** @file
2
3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 pxe_bc_mtftp.c
15
16 Abstract:
17 TFTP and MTFTP (multicast TFTP) implementation.
18
19 Revision History
20
21
22 **/
23
24 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
25
26 //
27 // The following #define is used to create a version that does not wait to
28 // open after a listen. This is just for a special regression test of MTFTP
29 // server to make sure multiple opens are handled correctly. Normally this
30 // next line should be a comment.
31 // #define SpecialNowaitVersion // comment out for normal operation
32 //
33
34 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
35 #include "bc.h"
36
37 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
38 UINT64
39 Swap64 (
40 UINT64 n
41 )
42 {
43 union {
44 UINT64 n;
45 UINT8 b[8];
46 } u;
47
48 UINT8 t;
49
50 u.n = n;
51
52 t = u.b[0];
53 u.b[0] = u.b[7];
54 u.b[7] = t;
55
56 t = u.b[1];
57 u.b[1] = u.b[6];
58 u.b[6] = t;
59
60 t = u.b[2];
61 u.b[2] = u.b[5];
62 u.b[5] = t;
63
64 t = u.b[3];
65 u.b[3] = u.b[4];
66 u.b[4] = t;
67
68 return u.n;
69 }
70
71 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
72
73 /**
74
75 @return EFI_SUCCESS :=
76 @return EFI_TFTP_ERROR :=
77 @return other :=
78
79 **/
80 STATIC
81 EFI_STATUS
82 TftpUdpRead (
83 PXE_BASECODE_DEVICE *Private,
84 UINT16 Operation,
85 VOID *HeaderPtr,
86 UINTN *BufferSizePtr,
87 VOID *BufferPtr,
88 EFI_IP_ADDRESS *ServerIpPtr,
89 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
90 EFI_IP_ADDRESS *OurIpPtr,
91 EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
92 UINT16 Timeout
93 )
94 {
95 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
96 EFI_STATUS Status;
97 EFI_EVENT TimeoutEvent;
98 UINTN HeaderSize;
99
100 //
101 //
102 //
103 Status = gBS->CreateEvent (
104 EVT_TIMER,
105 TPL_CALLBACK,
106 NULL,
107 NULL,
108 &TimeoutEvent
109 );
110
111 if (EFI_ERROR (Status)) {
112 return Status;
113 }
114
115 Status = gBS->SetTimer (
116 TimeoutEvent,
117 TimerRelative,
118 Timeout * 10000000 + 1000000
119 );
120
121 if (EFI_ERROR (Status)) {
122 gBS->CloseEvent (TimeoutEvent);
123 return Status;
124 }
125 //
126 //
127 //
128 HeaderSize = Private->BigBlkNumFlag ? sizeof (struct Tftpv4Ack8) : sizeof (struct Tftpv4Ack);
129
130 #define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)
131
132 Status = UdpRead (
133 Private,
134 Operation,
135 OurIpPtr,
136 OurPortPtr,
137 ServerIpPtr,
138 ServerPortPtr,
139 &HeaderSize,
140 HeaderPtr,
141 BufferSizePtr,
142 BufferPtr,
143 TimeoutEvent
144 );
145
146 if (Status != EFI_SUCCESS || ERROR_MESSAGE_PTR->OpCode != HTONS (TFTP_ERROR)) {
147 gBS->CloseEvent (TimeoutEvent);
148 return Status;
149 }
150 //
151 // got an error packet
152 // write one byte error code followed by error message
153 //
154 PxeBcMode = Private->EfiBc.Mode;
155 PxeBcMode->TftpErrorReceived = TRUE;
156 PxeBcMode->TftpError.ErrorCode = (UINT8) NTOHS (ERROR_MESSAGE_PTR->ErrCode);
157 HeaderSize = MIN (*BufferSizePtr, sizeof PxeBcMode->TftpError.ErrorString);
158 CopyMem (PxeBcMode->TftpError.ErrorString, BufferPtr, HeaderSize);
159
160 gBS->CloseEvent (TimeoutEvent);
161 return EFI_TFTP_ERROR;
162 }
163
164 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
165
166 /**
167
168
169 **/
170 STATIC
171 VOID
172 SendError (
173 PXE_BASECODE_DEVICE *Private,
174 EFI_IP_ADDRESS *ServerIpPtr,
175 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
176 EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr
177 )
178 {
179 struct Tftpv4Error *ErrStr;
180 UINTN Len;
181
182 ErrStr = (VOID *) Private->TftpErrorBuffer;
183 Len = sizeof *ErrStr;
184
185 ErrStr->OpCode = HTONS (TFTP_ERROR);
186 ErrStr->ErrCode = HTONS (TFTP_ERR_OPTION);
187 ErrStr->ErrMsg[0] = 0;
188
189 UdpWrite (
190 Private,
191 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
192 ServerIpPtr,
193 ServerPortPtr,
194 0,
195 0,
196 OurPortPtr,
197 0,
198 0,
199 &Len,
200 ErrStr
201 );
202 }
203
204 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
205
206 /**
207
208
209 **/
210 STATIC
211 EFI_STATUS
212 SendAckAndGetData (
213 PXE_BASECODE_DEVICE *Private,
214 EFI_IP_ADDRESS *ServerIpPtr,
215 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
216 EFI_IP_ADDRESS *ReplyIpPtr,
217 EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
218 UINT16 Timeout,
219 UINTN *ReplyLenPtr,
220 UINT8 *PxeBcMode,
221 UINT64 *BlockNumPtr,
222 BOOLEAN AckOnly
223 )
224 {
225 struct Tftpv4Data DataBuffer;
226 struct Tftpv4Ack *Ack2Ptr;
227 struct Tftpv4Ack8 *Ack8Ptr;
228 EFI_STATUS Status;
229 UINTN Len;
230
231 Ack2Ptr = (VOID *) Private->TftpAckBuffer;
232 Ack8Ptr = (VOID *) Private->TftpAckBuffer;
233
234 if (Private->BigBlkNumFlag) {
235 Len = sizeof (struct Tftpv4Ack8);
236
237 Ack8Ptr->OpCode = HTONS (TFTP_ACK8);
238 Ack8Ptr->BlockNum = Swap64 (*BlockNumPtr);
239
240 Status = UdpWrite (
241 Private,
242 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
243 ServerIpPtr,
244 ServerPortPtr,
245 0,
246 0,
247 OurPortPtr,
248 0,
249 0,
250 &Len,
251 Ack8Ptr
252 );
253
254 if (EFI_ERROR (Status)) {
255 return Status;
256 }
257 } else {
258 Len = sizeof (struct Tftpv4Ack);
259
260 Ack2Ptr->OpCode = HTONS (TFTP_ACK);
261 Ack2Ptr->BlockNum = HTONS ((UINT16) *BlockNumPtr);
262
263 Status = UdpWrite (
264 Private,
265 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
266 ServerIpPtr,
267 ServerPortPtr,
268 0,
269 0,
270 OurPortPtr,
271 0,
272 0,
273 &Len,
274 Ack2Ptr
275 );
276
277 if (EFI_ERROR (Status)) {
278 return Status;
279 }
280 }
281
282 if (AckOnly) {
283 //
284 // ACK of last packet. This is just a courtesy.
285 // Do not wait for response.
286 //
287 return EFI_SUCCESS;
288 }
289 //
290 // read reply
291 //
292 Status = TftpUdpRead (
293 Private,
294 0,
295 &DataBuffer,
296 ReplyLenPtr,
297 PxeBcMode,
298 ServerIpPtr,
299 ServerPortPtr,
300 ReplyIpPtr,
301 OurPortPtr,
302 Timeout
303 );
304
305 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
306 return Status;
307 }
308 //
309 // got a good reply (so far)
310 // check for next data packet
311 //
312 if (!Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA)) {
313 if (Status == EFI_BUFFER_TOO_SMALL) {
314 SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
315 }
316
317 *BlockNumPtr = NTOHS (DataBuffer.Header.BlockNum);
318 return Status;
319 }
320
321 if (Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA8)) {
322 if (Status == EFI_BUFFER_TOO_SMALL) {
323 SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
324 }
325
326 *BlockNumPtr = Swap64 (*(UINT64 *) &DataBuffer.Header.BlockNum);
327 return Status;
328 }
329
330 return EFI_PROTOCOL_ERROR;
331 }
332
333 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
334
335 /**
336
337
338 **/
339 STATIC
340 EFI_STATUS
341 LockStepReceive (
342 PXE_BASECODE_DEVICE *Private,
343 UINTN PacketSize,
344 UINT64 *BufferSizePtr,
345 UINT64 Offset,
346 UINT8 *BufferPtr,
347 EFI_IP_ADDRESS *ServerIpPtr,
348 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
349 EFI_IP_ADDRESS *ReplyIpPtr,
350 EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
351 UINT64 LastBlock,
352 UINT16 Timeout,
353 IN BOOLEAN DontUseBuffer
354 )
355 {
356 EFI_STATUS Status;
357 UINT64 BlockNum;
358 UINT64 BufferSize;
359 UINTN Retries;
360 UINTN SaveLen;
361 UINTN ReplyLen;
362
363 ReplyLen = PacketSize;
364 BlockNum = LastBlock;
365
366 DEBUG ((DEBUG_INFO, "\nLockStepReceive() PacketSize = %d", PacketSize));
367
368 if (DontUseBuffer) {
369 BufferSize = PacketSize;
370 } else {
371 BufferSize = *BufferSizePtr - Offset;
372 BufferPtr += Offset;
373 }
374
375 while (ReplyLen >= 512 && ReplyLen == PacketSize) {
376 if (BufferSize < PacketSize) {
377 ReplyLen = (UINTN) ((BufferSize > 0) ? BufferSize : 0);
378 }
379
380 SaveLen = ReplyLen;
381
382 //
383 // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout
384 //
385 Retries = NUM_ACK_RETRIES;
386
387 do {
388 ReplyLen = SaveLen;
389
390 Status = SendAckAndGetData (
391 Private,
392 ServerIpPtr,
393 ServerPortPtr,
394 ReplyIpPtr,
395 OurPortPtr,
396 Timeout,
397 (UINTN *) &ReplyLen,
398 BufferPtr,
399 &BlockNum,
400 FALSE
401 );
402
403 if (!EFI_ERROR (Status) || Status == EFI_BUFFER_TOO_SMALL) {
404 if (BlockNum == LastBlock) {
405 DEBUG ((DEBUG_NET, "\nresend"));
406 //
407 // a resend - continue
408 //
409 Status = EFI_TIMEOUT;
410 } else if (Private->BigBlkNumFlag) {
411 if (BlockNum != ++LastBlock) {
412 DEBUG ((DEBUG_NET, "\nLockStepReceive() Exit #1a"));
413 //
414 // not correct blocknum - error
415 //
416 return EFI_PROTOCOL_ERROR;
417 }
418 } else {
419 LastBlock = (LastBlock + 1) & 0xFFFF;
420 if (BlockNum != LastBlock) {
421 DEBUG ((DEBUG_NET, "\nLockStepReceive() Exit #1b"));
422 return EFI_PROTOCOL_ERROR;
423 //
424 // not correct blocknum - error
425 //
426 }
427 }
428 }
429 } while (Status == EFI_TIMEOUT && --Retries);
430
431 if (EFI_ERROR (Status)) {
432 if (Status != EFI_BUFFER_TOO_SMALL) {
433 SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
434 }
435
436 return Status;
437 }
438
439 if (DontUseBuffer) {
440 BufferSize += ReplyLen;
441 } else {
442 BufferPtr += ReplyLen;
443 BufferSize -= ReplyLen;
444 }
445 }
446 //
447 // while (ReplyLen == PacketSize);
448 //
449 if (DontUseBuffer) {
450 if (BufferSizePtr != NULL) {
451 *BufferSizePtr = (BufferSize - PacketSize);
452 }
453 } else {
454 *BufferSizePtr -= BufferSize;
455 }
456
457 /* Send ACK of last packet. */
458 ReplyLen = 0;
459
460 SendAckAndGetData (
461 Private,
462 ServerIpPtr,
463 ServerPortPtr,
464 ReplyIpPtr,
465 OurPortPtr,
466 Timeout,
467 (UINTN *) &ReplyLen,
468 BufferPtr,
469 &BlockNum,
470 TRUE
471 );
472
473 return EFI_SUCCESS;
474 }
475
476 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
477
478 //
479 // some literals
480 //
481 STATIC UINT8 Mode[] = MODE_BINARY;
482 STATIC UINT8 BlockSizeOp[] = OP_BLKSIZE;
483 STATIC UINT8 TsizeOp[] = OP_TFRSIZE;
484 STATIC UINT8 OverwriteOp[] = OP_OVERWRITE;
485 STATIC UINT8 BigBlkNumOp[] = OP_BIGBLKNUM;
486 STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort = TFTP_OPEN_PORT;
487
488 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
489
490 /**
491
492 @return Pointer to value field if option found or NULL if not found.
493
494 **/
495 STATIC
496 UINT8 *
497 FindOption (
498 UINT8 *OptionPtr,
499 INTN OpLen,
500 UINT8 *OackPtr,
501 INTN OackSize
502 )
503 {
504 if ((OackSize -= OpLen) <= 0) {
505 return NULL;
506 }
507
508 do {
509 if (!CompareMem (OackPtr, OptionPtr, OpLen)) {
510 return OackPtr + OpLen;
511 }
512
513 ++OackPtr;
514 } while (--OackSize);
515
516 return NULL;
517 }
518
519 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
520 #define BKSZOP 1 // block size
521 #define TSIZEOP 2 // transfer size
522 #define OVERWRITEOP 4 // overwrite
523 #define BIGBLKNUMOP 8 // big block numbers
524 STATIC
525 EFI_STATUS
526 TftpRwReq (
527 UINT16 Req,
528 UINT16 Options,
529 PXE_BASECODE_DEVICE *Private,
530 EFI_IP_ADDRESS *ServerIpPtr,
531 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
532 EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
533 UINT8 *FilenamePtr,
534 UINTN *PacketSizePtr,
535 VOID *Buffer
536 )
537 {
538 union {
539 UINT8 Data[514];
540 struct Tftpv4Req ReqStr;
541 } *u;
542
543 UINT16 OpFlags;
544 INTN Len;
545 INTN TotalLen;
546 UINT8 *Ptr;
547
548 if (*OurPortPtr == 0) {
549 OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;
550 } else {
551 OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT;
552 }
553 //
554 // build the basic request - opcode, filename, mode
555 //
556 u = Buffer;
557 u->ReqStr.OpCode = HTONS (Req);
558 TotalLen = sizeof (Mode) + sizeof (u->ReqStr.OpCode) + (Len = 1 + AsciiStrLen ((CHAR8 *) FilenamePtr));
559
560 CopyMem (u->ReqStr.FileName, FilenamePtr, Len);
561 Ptr = (UINT8 *) (u->ReqStr.FileName + Len);
562
563 CopyMem (Ptr, Mode, sizeof (Mode));
564 Ptr += sizeof (Mode);
565
566 if (Options & BKSZOP) {
567 CopyMem (Ptr, BlockSizeOp, sizeof (BlockSizeOp));
568 UtoA10 (*PacketSizePtr, Ptr + sizeof (BlockSizeOp));
569
570 TotalLen += (Len = 1 + AsciiStrLen ((CHAR8 *) (Ptr + sizeof (BlockSizeOp))) + sizeof (BlockSizeOp));
571
572 Ptr += Len;
573 }
574
575 if (Options & TSIZEOP) {
576 CopyMem (Ptr, TsizeOp, sizeof (TsizeOp));
577 CopyMem (Ptr + sizeof (TsizeOp), "0", 2);
578 TotalLen += sizeof (TsizeOp) + 2;
579 Ptr += sizeof (TsizeOp) + 2;
580 }
581
582 if (Options & OVERWRITEOP) {
583 CopyMem (Ptr, OverwriteOp, sizeof (OverwriteOp));
584 CopyMem (Ptr + sizeof (OverwriteOp), "1", 2);
585 TotalLen += sizeof (OverwriteOp) + 2;
586 Ptr += sizeof (OverwriteOp) + 2;
587 }
588
589 if (Options & BIGBLKNUMOP) {
590 CopyMem (Ptr, BigBlkNumOp, sizeof (BigBlkNumOp));
591 CopyMem (Ptr + sizeof (BigBlkNumOp), "8", 2);
592 TotalLen += sizeof (BigBlkNumOp) + 2;
593 Ptr += sizeof (BigBlkNumOp) + 2;
594 }
595 //
596 // send it
597 //
598 return UdpWrite (
599 Private,
600 OpFlags,
601 ServerIpPtr,
602 ServerPortPtr,
603 0,
604 0,
605 OurPortPtr,
606 0,
607 0,
608 (UINTN *) &TotalLen,
609 u
610 );
611 }
612
613 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
614
615 /**
616
617
618 **/
619 STATIC
620 EFI_STATUS
621 TftpRwReqwResp (
622 UINT16 Req,
623 UINT16 Options,
624 PXE_BASECODE_DEVICE *Private,
625 VOID *HeaderPtr,
626 UINTN *PacketSizePtr,
627 UINTN *ReplyLenPtr,
628 VOID *BufferPtr,
629 EFI_IP_ADDRESS *ServerIpPtr,
630 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
631 EFI_PXE_BASE_CODE_UDP_PORT *ServerReplyPortPtr,
632 EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
633 UINT8 *FilenamePtr,
634 UINT16 Timeout
635 )
636 {
637 EFI_STATUS Status;
638 UINTN SaveReplyLen;
639 INTN Retries;
640 UINT8 Buffer[514];
641
642 SaveReplyLen = *ReplyLenPtr;
643 Retries = 3;
644 Private->BigBlkNumFlag = FALSE;
645 *OurPortPtr = 0;
646 //
647 // generate random
648 //
649 do {
650 if (*OurPortPtr != 0) {
651 if (++ *OurPortPtr == 0) {
652 *OurPortPtr = PXE_RND_PORT_LOW;
653 }
654 }
655 //
656 // send request from our Ip = StationIp
657 //
658 if ((Status = TftpRwReq (
659 Req,
660 Options,
661 Private,
662 ServerIpPtr,
663 ServerPortPtr,
664 OurPortPtr,
665 FilenamePtr,
666 PacketSizePtr,
667 Buffer
668 )) != EFI_SUCCESS) {
669 DEBUG (
670 (DEBUG_WARN,
671 "\nTftpRwReqwResp() Exit #1 %xh (%r)",
672 Status,
673 Status)
674 );
675
676 return Status;
677 }
678 //
679 // read reply to our Ip = StationIp
680 //
681 *ReplyLenPtr = SaveReplyLen;
682
683 Status = TftpUdpRead (
684 Private,
685 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
686 HeaderPtr,
687 ReplyLenPtr,
688 BufferPtr,
689 ServerIpPtr,
690 ServerReplyPortPtr,
691 0,
692 OurPortPtr,
693 Timeout
694 );
695 } while (Status == EFI_TIMEOUT && --Retries);
696
697 if (!Options || Status != EFI_TFTP_ERROR) {
698 DEBUG (
699 (DEBUG_WARN,
700 "\nTftpRwReqwResp() Exit #2 %xh (%r)",
701 Status,
702 Status)
703 );
704 return Status;
705 }
706
707 Status = TftpRwReqwResp (
708 Req,
709 0,
710 Private,
711 HeaderPtr,
712 PacketSizePtr,
713 ReplyLenPtr,
714 BufferPtr,
715 ServerIpPtr,
716 ServerPortPtr,
717 ServerReplyPortPtr,
718 OurPortPtr,
719 FilenamePtr,
720 Timeout
721 );
722
723 DEBUG ((DEBUG_WARN, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status, Status));
724
725 return Status;
726 }
727
728 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
729
730 //
731 // mtftp listen
732 // read on mcast ip, cport, from sport, for data packet
733 // returns success if gets multicast last packet or all up to last block
734 // if not missing, then finished
735 //
736
737 /**
738
739
740 **/
741 STATIC
742 EFI_STATUS
743 MtftpListen (
744 PXE_BASECODE_DEVICE *Private,
745 UINT64 *BufferSizePtr,
746 UINT8 *BufferPtr,
747 EFI_IP_ADDRESS *ServerIpPtr,
748 EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr,
749 UINT64 *StartBlockPtr,
750 UINTN *NumMissedPtr,
751 UINT16 TransTimeout,
752 UINT16 ListenTimeout,
753 UINT64 FinalBlock,
754 IN BOOLEAN DontUseBuffer
755 )
756 {
757 EFI_STATUS Status;
758 struct Tftpv4Ack Header;
759 UINT64 Offset;
760 UINT64 BlockNum;
761 UINT64 LastBlockNum;
762 UINT64 BufferSize;
763 UINTN NumMissed;
764 UINTN PacketSize;
765 UINTN SaveReplyLen;
766 UINTN ReplyLen;
767 UINT16 Timeout;
768
769 LastBlockNum = *StartBlockPtr;
770 Timeout = ListenTimeout;
771 *NumMissedPtr = 0;
772 PacketSize = 0;
773 BufferSize = *BufferSizePtr;
774 ReplyLen = MAX_TFTP_PKT_SIZE;;
775
776 //
777 // receive
778 //
779 do {
780 if ((SaveReplyLen = ReplyLen) > BufferSize) {
781 SaveReplyLen = 0;
782 }
783
784 /* %%TBD - add big block number support */
785
786 //
787 // get data - loop on resends
788 //
789 do {
790 ReplyLen = SaveReplyLen;
791
792 if ((Status = TftpUdpRead (
793 Private,
794 0,
795 &Header,
796 &ReplyLen,
797 BufferPtr,
798 ServerIpPtr,
799 &MtftpInfoPtr->SPort,
800 &MtftpInfoPtr->MCastIp,
801 &MtftpInfoPtr->CPort,
802 Timeout
803 )) != EFI_SUCCESS) {
804 return Status;
805 }
806 //
807 // make sure a data packet
808 //
809 if (Header.OpCode != HTONS (TFTP_DATA)) {
810 return EFI_PROTOCOL_ERROR;
811 }
812 } while ((BlockNum = NTOHS (Header.BlockNum)) == LastBlockNum);
813
814 //
815 // make sure still going up
816 //
817 if (LastBlockNum > BlockNum) {
818 return EFI_PROTOCOL_ERROR;
819 }
820
821 if (BlockNum - LastBlockNum > 0xFFFFFFFF) {
822 return EFI_PROTOCOL_ERROR;
823 } else {
824 NumMissed = (UINTN) (BlockNum - LastBlockNum - 1);
825 }
826
827 LastBlockNum = BlockNum;
828
829 //
830 // if first time through, some reinitialization
831 //
832 if (!PacketSize) {
833 *StartBlockPtr = BlockNum;
834 PacketSize = ReplyLen;
835 Timeout = TransTimeout;
836 } else {
837 *NumMissedPtr = (UINT16) (*NumMissedPtr + NumMissed);
838 }
839 //
840 // if missed packets, update start block,
841 // etc. and move packet to proper place in buffer
842 //
843 if (NumMissed) {
844 *StartBlockPtr = BlockNum;
845 if (!DontUseBuffer) {
846 Offset = NumMissed * PacketSize;
847 CopyMem (BufferPtr + Offset, BufferPtr, ReplyLen);
848 BufferPtr += Offset;
849 BufferSize -= Offset;
850 }
851 }
852
853 if (!DontUseBuffer) {
854 BufferPtr += ReplyLen;
855 BufferSize -= ReplyLen;
856 }
857 } while (ReplyLen == PacketSize && BlockNum != FinalBlock);
858
859 *BufferSizePtr = BufferSize;
860
861 return EFI_SUCCESS;
862 }
863
864 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
865
866 /**
867
868 @return // mtftp open session
869 @return // return code EFI_SUCCESS
870 @return // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
871 @return // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
872 @return // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
873 @retval GOTUNI returns NO_DATA go will go to TFTP session)
874
875 **/
876 STATIC
877 EFI_STATUS
878 MtftpOpen (
879 PXE_BASECODE_DEVICE * Private,
880 UINT64 *BufferSizePtr,
881 UINT8 *BufferPtr,
882 UINTN *PacketSizePtr,
883 EFI_IP_ADDRESS * ServerIpPtr,
884 UINT8 *FilenamePtr,
885 EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr,
886 UINT8 *CompletionStatusPtr,
887 #define GOTUNI 1
888 #define GOTMULTI 2
889 IN BOOLEAN DontUseBuffer
890 )
891 {
892 EFI_STATUS Status;
893 EFI_IP_ADDRESS OurReplyIp;
894 struct Tftpv4Ack Header;
895 INTN ReplyLen;
896 INTN Retries;
897 UINT8 *BufferPtr2;
898 UINT8 TmpBuf[514];
899
900 Retries = NUM_MTFTP_OPEN_RETRIES;
901 BufferPtr2 = BufferPtr;
902 *PacketSizePtr = (UINTN) (MIN (*BufferSizePtr, MAX_TFTP_PKT_SIZE));
903
904 do {
905 //
906 // send a read request
907 //
908 *CompletionStatusPtr = 0;
909
910 if ((Status = TftpRwReq (
911 TFTP_RRQ,
912 0,
913 Private,
914 ServerIpPtr,
915 &MtftpInfoPtr->SPort,
916 &MtftpInfoPtr->CPort,
917 FilenamePtr,
918 PacketSizePtr,
919 TmpBuf
920 )) != EFI_SUCCESS) {
921 return Status;
922 }
923
924 for (;;) {
925 //
926 // read reply
927 //
928 ZeroMem (&OurReplyIp, Private->IpLength);
929 ReplyLen = *PacketSizePtr;
930
931 if ((Status = TftpUdpRead (
932 Private,
933 EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER,
934 &Header,
935 (UINTN *) &ReplyLen,
936 BufferPtr2,
937 ServerIpPtr,
938 &MtftpInfoPtr->SPort,
939 &OurReplyIp,
940 &MtftpInfoPtr->CPort,
941 MtftpInfoPtr->TransmitTimeout
942 )) == EFI_SUCCESS) {
943 //
944 // check for first data packet
945 //
946 if (Header.OpCode != HTONS (TFTP_DATA)) {
947 return EFI_PROTOCOL_ERROR;
948 }
949 //
950 // check block num
951 //
952 if (Header.BlockNum != HTONS (1)) {
953 //
954 // it's not first
955 // if we are not the primary client,
956 // we probably got first and now second
957 // multicast but no unicast, so
958 // *CompletionStatusPtr = GOTMULTI - if this is
959 // the second, can just go on to listen
960 // starting with 2 as the last block
961 // received
962 //
963 if (Header.BlockNum != HTONS (2)) {
964 //
965 // not second
966 //
967 *CompletionStatusPtr = 0;
968 }
969
970 return Status;
971 }
972
973 //
974 // now actual
975 //
976 *PacketSizePtr = ReplyLen;
977 //
978 // see if a unicast data packet
979 //
980 if (!CompareMem (
981 &OurReplyIp,
982 &Private->EfiBc.Mode->StationIp,
983 Private->IpLength
984 )) {
985 *CompletionStatusPtr |= GOTUNI;
986 //
987 // it is
988 // if already got multicast packet,
989 // got em both
990 //
991 if (*CompletionStatusPtr & GOTMULTI) {
992 break;
993 }
994 } else if (!CompareMem (
995 &OurReplyIp,
996 &MtftpInfoPtr->MCastIp,
997 Private->IpLength
998 )) {
999 //
1000 // otherwise see if a multicast data packet
1001 //
1002 *CompletionStatusPtr |= GOTMULTI;
1003 //
1004 // it is
1005 // got first - bump pointer so that if
1006 // second multi comes along, we're OK
1007 //
1008 if (!DontUseBuffer) {
1009 BufferPtr2 = (UINT8 *) BufferPtr + ReplyLen;
1010 }
1011 //
1012 // if already got unicast packet,
1013 // got em both
1014 //
1015 if (*CompletionStatusPtr & GOTUNI) {
1016 break;
1017 }
1018 } else {
1019 //
1020 // else protocol error
1021 //
1022 return EFI_PROTOCOL_ERROR;
1023 }
1024 } else if (Status == EFI_TIMEOUT) {
1025 //
1026 // bad return code - if timed out, retry
1027 //
1028 break;
1029 } else {
1030 //
1031 // else just bad - failed MTFTP open
1032 //
1033 return Status;
1034 }
1035 }
1036 } while (Status == EFI_TIMEOUT && --Retries);
1037
1038 if (Status != EFI_SUCCESS) {
1039 //
1040 // open failed
1041 //
1042 return Status;
1043 }
1044 //
1045 // got em both - go into receive mode
1046 // routine to read rest of file after a successful open (TFTP or MTFTP)
1047 // sends ACK and gets next data packet until short packet arrives,
1048 // then sends ACK and (hopefully) times out
1049 //
1050 return LockStepReceive (
1051 Private,
1052 (UINT16) ReplyLen,
1053 BufferSizePtr,
1054 ReplyLen,
1055 BufferPtr,
1056 ServerIpPtr,
1057 &MtftpInfoPtr->SPort,
1058 &MtftpInfoPtr->MCastIp,
1059 &MtftpInfoPtr->CPort,
1060 1,
1061 MtftpInfoPtr->TransmitTimeout,
1062 DontUseBuffer
1063 );
1064 }
1065
1066 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1067
1068 /**
1069
1070
1071 **/
1072 STATIC
1073 EFI_STATUS
1074 MtftpDownload (
1075 PXE_BASECODE_DEVICE *Private,
1076 UINT64 *BufferSizePtr,
1077 UINT8 *BufferPtr,
1078 EFI_IP_ADDRESS *ServerIpPtr,
1079 UINT8 *FilenamePtr,
1080 EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr,
1081 IN BOOLEAN DontUseBuffer
1082 )
1083 {
1084 EFI_PXE_BASE_CODE_IP_FILTER Filter;
1085 EFI_STATUS Status;
1086 UINT64 StartBlock;
1087 UINT64 LastBlock;
1088 UINT64 LastStartBlock;
1089 UINT64 BufferSize;
1090 UINTN Offset;
1091 UINTN NumMissed;
1092 UINT16 TransTimeout;
1093 UINT16 ListenTimeout;
1094 UINT8 *BufferPtrLocal;
1095
1096 TransTimeout = MtftpInfoPtr->TransmitTimeout;
1097 ListenTimeout = MtftpInfoPtr->ListenTimeout;
1098 LastBlock = 0;
1099 LastStartBlock = 0;
1100 Offset = 0;
1101
1102 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
1103 Filter.IpCnt = 2;
1104 CopyMem (&Filter.IpList[0], &Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS));
1105 CopyMem (&Filter.IpList[1], &MtftpInfoPtr->MCastIp, sizeof (EFI_IP_ADDRESS));
1106
1107 if ((Status = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1108 return Status;
1109 }
1110
1111 for (;;) {
1112 StartBlock = LastStartBlock;
1113 BufferSize = *BufferSizePtr - Offset;
1114
1115 if (DontUseBuffer) {
1116 //
1117 // overwrie the temp buf
1118 //
1119 BufferPtrLocal = BufferPtr;
1120 } else {
1121 BufferPtrLocal = BufferPtr + Offset;
1122
1123 }
1124 //
1125 // special !!! do not leave enabled in saved version on Source Safe
1126 // Following code put in in order to create a special version for regression
1127 // test of MTFTP server to make sure it handles mulitple opens correctly.
1128 // This code should NOT be enabled normally.
1129 //
1130 if (((Status = MtftpListen (
1131 Private,
1132 &BufferSize,
1133 BufferPtrLocal,
1134 ServerIpPtr,
1135 MtftpInfoPtr,
1136 &StartBlock,
1137 &NumMissed,
1138 TransTimeout,
1139 ListenTimeout,
1140 LastBlock,
1141 DontUseBuffer
1142 )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) {
1143 return Status;
1144 //
1145 // failed
1146 //
1147 }
1148 //
1149 // if none were received, start block is not reset
1150 //
1151 if (StartBlock == LastStartBlock) {
1152 UINT8 CompStat;
1153
1154 //
1155 // timed out with none received - try MTFTP open
1156 //
1157 if ((Status = MtftpOpen (
1158 Private,
1159 BufferSizePtr,
1160 BufferPtr,
1161 &Offset,
1162 ServerIpPtr,
1163 FilenamePtr,
1164 MtftpInfoPtr,
1165 &CompStat,
1166 DontUseBuffer
1167 )) != EFI_SUCCESS) {
1168 //
1169 // open failure - try TFTP
1170 //
1171 return Status;
1172 }
1173 //
1174 // return code EFI_SUCCESS
1175 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1176 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1177 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1178 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1179 //
1180 if (CompStat == (GOTUNI | GOTMULTI)) {
1181 //
1182 // finished - got it all
1183 //
1184 return Status;
1185 }
1186
1187 if (CompStat) {
1188 //
1189 // offset is two packet lengths
1190 //
1191 Offset <<= 1;
1192 //
1193 // last block received
1194 //
1195 LastStartBlock = 2;
1196 } else {
1197 Offset = 0;
1198 LastStartBlock = 0;
1199 }
1200
1201 ListenTimeout = TransTimeout;
1202 continue;
1203 }
1204 //
1205 // did we get the last block
1206 //
1207 if (Status == EFI_SUCCESS) {
1208 //
1209 // yes - set the file size if this was first time
1210 //
1211 if (!LastBlock) {
1212 *BufferSizePtr -= BufferSize;
1213 }
1214 //
1215 // if buffer was too small, finished
1216 //
1217 if (!DontUseBuffer) {
1218 return EFI_BUFFER_TOO_SMALL;
1219 }
1220 //
1221 // if we got them all, finished
1222 //
1223 if (!NumMissed && StartBlock == LastStartBlock + 1) {
1224 return Status;
1225 }
1226 //
1227 // did not get them all - set last block
1228 //
1229 LastBlock = (UINT16) (StartBlock - 1);
1230 }
1231 //
1232 // compute listen timeout
1233 //
1234 ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed));
1235
1236 //
1237 // reset
1238 //
1239 Offset = 0;
1240 LastStartBlock = 0;
1241 }
1242 }
1243
1244 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1245
1246 /**
1247
1248
1249 **/
1250 STATIC
1251 EFI_STATUS
1252 TftpInfo (
1253 PXE_BASECODE_DEVICE *Private,
1254 UINT64 *BufferSizePtr,
1255 EFI_IP_ADDRESS *ServerIpPtr,
1256 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
1257 UINT8 *FilenamePtr,
1258 UINTN *PacketSizePtr
1259 )
1260 {
1261 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1262 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1263 EFI_STATUS Status;
1264 UINT64 BlockNum;
1265 UINTN Offset;
1266 UINTN ReplyLen;
1267 UINT8 *Ptr;
1268
1269 union {
1270 struct Tftpv4Oack OAck2Ptr;
1271 struct Tftpv4Ack Ack2Ptr;
1272 struct Tftpv4Data Datastr;
1273 } u;
1274
1275 OurPort = 0;
1276 ServerReplyPort = 0;
1277 ReplyLen = sizeof (u.Datastr.Data);
1278
1279 //
1280 // send a write request with the blocksize option -
1281 // sets our IP and port - and receive reply - sets his port
1282 // will retry operation up to 3 times if no response,
1283 // and will retry without options on an error reply
1284 //
1285 if ((Status = TftpRwReqwResp (
1286 TFTP_RRQ,
1287 /* BIGBLKNUMOP | */BKSZOP | TSIZEOP,
1288 Private,
1289 &u,
1290 PacketSizePtr,
1291 &ReplyLen,
1292 u.Datastr.Data,
1293 ServerIpPtr,
1294 &SrvPort,
1295 &ServerReplyPort,
1296 &OurPort,
1297 FilenamePtr,
1298 REQ_RESP_TIMEOUT
1299 )) != EFI_SUCCESS) {
1300 DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #1"));
1301 return Status;
1302 }
1303 //
1304 // check for good OACK
1305 //
1306 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1307 //
1308 // now parse it for options
1309 // bigblk#
1310 //
1311 Ptr = FindOption (
1312 BigBlkNumOp,
1313 sizeof (BigBlkNumOp),
1314 u.OAck2Ptr.OpAck[0].Option,
1315 ReplyLen + sizeof (u.Ack2Ptr.BlockNum)
1316 );
1317
1318 if (Ptr != NULL) {
1319 if (AtoU (Ptr) == 8) {
1320 Private->BigBlkNumFlag = TRUE;
1321 } else {
1322 return EFI_PROTOCOL_ERROR;
1323 }
1324 }
1325 //
1326 // blksize
1327 //
1328 Ptr = FindOption (
1329 BlockSizeOp,
1330 sizeof (BlockSizeOp),
1331 u.OAck2Ptr.OpAck[0].Option,
1332 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
1333 );
1334
1335 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
1336
1337 //
1338 // tsize
1339 //
1340 Ptr = FindOption (
1341 TsizeOp,
1342 sizeof (TsizeOp),
1343 u.OAck2Ptr.OpAck[0].Option,
1344 ReplyLen
1345 );
1346
1347 if (Ptr != NULL) {
1348 *BufferSizePtr = AtoU64 (Ptr);
1349
1350 //
1351 // teminate session with error
1352 //
1353 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
1354
1355 return EFI_SUCCESS;
1356 }
1357
1358 Offset = 0;
1359 BlockNum = 0;
1360 } else {
1361 //
1362 // if MTFTP get filesize, return unsupported
1363 //
1364 if (SrvPort != TftpRequestPort) {
1365 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
1366 DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #3"));
1367 return EFI_UNSUPPORTED;
1368 }
1369
1370 Offset = ReplyLen;
1371 //
1372 // last block received
1373 //
1374 BlockNum = 1;
1375 }
1376 //
1377 // does not support the option - do a download with no buffer
1378 //
1379 *BufferSizePtr = 0;
1380
1381 Status = LockStepReceive (
1382 Private,
1383 (UINT16) ReplyLen,
1384 BufferSizePtr,
1385 Offset,
1386 (UINT8 *) &u,
1387 ServerIpPtr,
1388 &ServerReplyPort,
1389 &Private->EfiBc.Mode->StationIp,
1390 &OurPort,
1391 BlockNum,
1392 ACK_TIMEOUT,
1393 TRUE
1394 );
1395
1396 if (Status != EFI_SUCCESS) {
1397 DEBUG ((DEBUG_WARN, "\nTftpInfo() LockStepReceive() == %Xh", Status));
1398 }
1399
1400 if (Status != EFI_BUFFER_TOO_SMALL) {
1401 return Status;
1402 }
1403
1404 return EFI_SUCCESS;
1405 }
1406
1407 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1408
1409 /**
1410
1411
1412 **/
1413 STATIC
1414 EFI_STATUS
1415 TftpDownload (
1416 PXE_BASECODE_DEVICE *Private,
1417 UINT64 *BufferSizePtr,
1418 UINT8 *BufferPtr,
1419 EFI_IP_ADDRESS *ServerIpPtr,
1420 UINT8 *FilenamePtr,
1421 UINTN *PacketSizePtr,
1422 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
1423 UINT16 Req,
1424 IN BOOLEAN DontUseBuffer
1425 )
1426 {
1427 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1428 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1429 EFI_STATUS Status;
1430 UINT64 Offset;
1431 UINT64 BlockNum;
1432 UINTN ReplyLen;
1433 UINT8 *Ptr;
1434
1435 union {
1436 struct Tftpv4Ack Ack2Ptr;
1437 struct Tftpv4Oack OAck2Ptr;
1438 struct Tftpv4Data Data;
1439 struct Tftpv4Ack8 Ack8Ptr;
1440 struct Tftpv4Data8 Data8;
1441 } U;
1442
1443 OurPort = 0;
1444 ServerReplyPort = 0;
1445 ReplyLen = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr);
1446
1447 //
1448 // send a read request with the blocksize option - sets our IP and port
1449 // - and receive reply - sets his port will retry operation up to 3
1450 // times if no response, and will retry without options on an error
1451 // reply
1452 //
1453 if ((Status = TftpRwReqwResp (
1454 Req,
1455 /* BIGBLKNUMOP | */BKSZOP,
1456 Private,
1457 &U,
1458 PacketSizePtr,
1459 &ReplyLen,
1460 BufferPtr,
1461 ServerIpPtr,
1462 &SrvPort,
1463 &ServerReplyPort,
1464 &OurPort,
1465 FilenamePtr,
1466 REQ_RESP_TIMEOUT
1467 )) != EFI_SUCCESS) {
1468 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #1 %xh (%r)", Status, Status));
1469 return Status;
1470 }
1471 //
1472 // check for OACK
1473 //
1474 if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1475 //
1476 // get the OACK
1477 //
1478 CopyMem (U.Data.Data, BufferPtr, ReplyLen);
1479
1480 Ptr = FindOption (
1481 BigBlkNumOp,
1482 sizeof (BigBlkNumOp),
1483 U.OAck2Ptr.OpAck[0].Option,
1484 ReplyLen + sizeof (U.Ack2Ptr.BlockNum)
1485 );
1486
1487 if (Ptr != NULL) {
1488 if (AtoU (Ptr) == 8) {
1489 Private->BigBlkNumFlag = TRUE;
1490 } else {
1491 return EFI_PROTOCOL_ERROR;
1492 }
1493 }
1494 //
1495 // now parse it for blocksize option
1496 //
1497 Ptr = FindOption (
1498 BlockSizeOp,
1499 sizeof (BlockSizeOp),
1500 U.OAck2Ptr.OpAck[0].Option,
1501 ReplyLen += sizeof (U.Ack2Ptr.BlockNum)
1502 );
1503
1504 ReplyLen = (Ptr != NULL) ? AtoU (Ptr) : 512;
1505
1506 Offset = 0;
1507 //
1508 // last block received
1509 //
1510 BlockNum = 0;
1511 } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) {
1512 //
1513 // or data
1514 //
1515 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #2 %xh (%r)", Status, Status));
1516
1517 return EFI_PROTOCOL_ERROR;
1518 } else {
1519 //
1520 // got good data packet
1521 //
1522 Offset = ReplyLen;
1523 //
1524 // last block received
1525 //
1526 BlockNum = 1;
1527 }
1528
1529 if (PacketSizePtr != NULL) {
1530 *PacketSizePtr = ReplyLen;
1531 }
1532 //
1533 // routine to read rest of file after a successful open (TFTP or MTFTP)
1534 // sends ACK and gets next data packet until short packet arrives, then sends
1535 // ACK and (hopefully) times out
1536 // if first packet has been read, BufferPtr and BufferSize must reflect fact
1537 //
1538 Status = LockStepReceive (
1539 Private,
1540 ReplyLen,
1541 BufferSizePtr,
1542 Offset,
1543 BufferPtr,
1544 ServerIpPtr,
1545 &ServerReplyPort,
1546 &Private->EfiBc.Mode->StationIp,
1547 &OurPort,
1548 BlockNum,
1549 ACK_TIMEOUT,
1550 DontUseBuffer
1551 );
1552
1553 if (Status != EFI_SUCCESS) {
1554 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #3 %xh (%r)", Status, Status));
1555
1556 if (Status == EFI_BUFFER_TOO_SMALL) {
1557 Status = TftpInfo (
1558 Private,
1559 BufferSizePtr,
1560 ServerIpPtr,
1561 SrvPort,
1562 FilenamePtr,
1563 PacketSizePtr
1564 );
1565
1566 if (!EFI_ERROR (Status)) {
1567 Status = EFI_BUFFER_TOO_SMALL;
1568 }
1569 }
1570 }
1571
1572 return Status;
1573 }
1574
1575 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1576
1577 /**
1578
1579
1580 **/
1581 STATIC
1582 EFI_STATUS
1583 TftpUpload (
1584 PXE_BASECODE_DEVICE *Private,
1585 UINT64 *BufferSizePtr,
1586 VOID *BufferPtr,
1587 EFI_IP_ADDRESS *ServerIpPtr,
1588 UINT8 *FilenamePtr,
1589 UINTN *PacketSizePtr,
1590 BOOLEAN Overwrite
1591 )
1592 {
1593 struct Tftpv4Ack Header;
1594 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1595 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1596 EFI_STATUS Status;
1597 UINT64 BlockNum;
1598 UINT64 TransferSize;
1599 UINTN ReplyLen;
1600 UINTN TransferLen;
1601 UINT16 Options;
1602 UINT8 *Ptr;
1603
1604 union {
1605 struct Tftpv4Oack OAck2Ptr;
1606 struct Tftpv4Ack Ack2Ptr;
1607 struct Tftpv4Data Datastr;
1608 } u;
1609
1610 OurPort = 0;
1611 ServerReplyPort = 0;
1612 TransferSize = *BufferSizePtr;
1613 ReplyLen = sizeof (u.Datastr.Data);
1614 Options = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP);
1615
1616 //
1617 // send a write request with the blocksize option - sets our IP and port -
1618 // and receive reply - sets his port
1619 // will retry operation up to 3 times if no response, and will retry without
1620 // options on an error reply
1621 //
1622 if ((Status = TftpRwReqwResp (
1623 TFTP_WRQ,
1624 Options,
1625 Private,
1626 &u,
1627 PacketSizePtr,
1628 &ReplyLen,
1629 u.Datastr.Data,
1630 ServerIpPtr,
1631 &TftpRequestPort,
1632 &ServerReplyPort,
1633 &OurPort,
1634 FilenamePtr,
1635 REQ_RESP_TIMEOUT
1636 )) != EFI_SUCCESS) {
1637 return Status;
1638 }
1639 //
1640 // check for OACK
1641 //
1642 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1643 //
1644 // parse it for blocksize option
1645 //
1646 Ptr = FindOption (
1647 BlockSizeOp,
1648 sizeof (BlockSizeOp),
1649 u.OAck2Ptr.OpAck[0].Option,
1650 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
1651 );
1652 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
1653 }
1654 //
1655 // or ACK
1656 //
1657 else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) {
1658 //
1659 // option was not supported
1660 //
1661 *PacketSizePtr = 512;
1662 } else {
1663 return EFI_PROTOCOL_ERROR;
1664 }
1665 //
1666 // loop
1667 //
1668 Header.OpCode = HTONS (TFTP_DATA);
1669 BlockNum = 1;
1670 Header.BlockNum = HTONS (1);
1671
1672 do {
1673 UINTN HeaderSize;
1674 INTN Retries;
1675
1676 Retries = NUM_ACK_RETRIES;
1677 HeaderSize = sizeof (Header);
1678 TransferLen = (UINTN) (MIN (*PacketSizePtr, TransferSize));
1679
1680 //
1681 // write a data packet and get an ack
1682 //
1683 do {
1684 //
1685 // write
1686 //
1687 if ((Status = UdpWrite (
1688 Private,
1689 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
1690 ServerIpPtr,
1691 &ServerReplyPort,
1692 0,
1693 0,
1694 &OurPort,
1695 &HeaderSize,
1696 &Header,
1697 &TransferLen,
1698 BufferPtr
1699 )) != EFI_SUCCESS) {
1700 return Status;
1701 }
1702 //
1703 // read reply
1704 //
1705 ReplyLen = sizeof (u.Datastr.Data);
1706
1707 if ((Status = TftpUdpRead (
1708 Private,
1709 0,
1710 &u,
1711 &ReplyLen,
1712 u.Datastr.Data,
1713 ServerIpPtr,
1714 &ServerReplyPort,
1715 0,
1716 &OurPort,
1717 ACK_TIMEOUT
1718 )) == EFI_SUCCESS) {
1719 //
1720 // check for ACK for this data packet
1721 //
1722 if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) {
1723 return EFI_PROTOCOL_ERROR;
1724 }
1725
1726 if (u.Ack2Ptr.BlockNum != Header.BlockNum) {
1727 //
1728 // not for this packet - continue
1729 //
1730 Status = EFI_TIMEOUT;
1731 }
1732 }
1733 } while (Status == EFI_TIMEOUT && --Retries);
1734
1735 if (Status != EFI_SUCCESS) {
1736 return Status;
1737 }
1738
1739 BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen);
1740 TransferSize -= TransferLen;
1741 ++BlockNum;
1742 Header.BlockNum = HTONS ((UINT16) BlockNum);
1743 } while (TransferLen == *PacketSizePtr);
1744
1745 return EFI_SUCCESS;
1746 }
1747
1748 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1749
1750 /**
1751
1752 @return * EFI_INVALID_PARAMETER
1753 @return * EFI_OUT_OF_RESOURCES
1754 @return * EFI_BAD_BUFFER_SIZE
1755 @return * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
1756 @return * TftpDownload() and TftpUpload().
1757
1758 **/
1759 EFI_STATUS
1760 PxeBcMtftp (
1761 PXE_BASECODE_DEVICE *Private,
1762 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
1763 UINT64 *BufferSizePtr,
1764 VOID *BufferPtr,
1765 EFI_IP_ADDRESS *ServerIpPtr,
1766 UINT8 *FilenamePtr,
1767 UINTN *PacketSizePtr,
1768 IN EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, OPTIONAL
1769 IN BOOLEAN Overwrite,
1770 IN BOOLEAN DontUseBuffer
1771 )
1772 {
1773 EFI_PXE_BASE_CODE_IP_FILTER Filter;
1774 EFI_STATUS StatCode;
1775 EFI_STATUS Status;
1776 UINT64 BufferSizeLocal;
1777 UINTN PacketSize;
1778 UINT8 *BufferPtrLocal;
1779
1780 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
1781 Filter.IpCnt = 0;
1782 Filter.reserved = 0;
1783
1784 /* No error has occurred, yet. */
1785 Private->EfiBc.Mode->TftpErrorReceived = FALSE;
1786
1787 /* We must at least have an MTFTP server IP address and
1788 * a pointer to the buffer size.
1789 */
1790 if (!ServerIpPtr || !BufferSizePtr) {
1791 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #1"));
1792
1793 return EFI_INVALID_PARAMETER;
1794 }
1795
1796 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;
1797
1798 //
1799 // make sure filter set to unicast at start
1800 //
1801 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1802 DEBUG (
1803 (DEBUG_NET,
1804 "\nPxeBcMtftp() Exit IpFilter() == %Xh",
1805 StatCode)
1806 );
1807
1808 return StatCode;
1809 }
1810 //
1811 // set unset parms to default values
1812 //
1813 if (!PacketSizePtr) {
1814 *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;
1815 }
1816
1817 if ((*PacketSizePtr > *BufferSizePtr) &&
1818 (Operation != EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) &&
1819 (Operation != EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE)) {
1820 *PacketSizePtr = MAX ((UINTN) *BufferSizePtr, MIN_TFTP_PKT_SIZE);
1821 }
1822
1823 if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {
1824 *PacketSizePtr = MIN_TFTP_PKT_SIZE;
1825 return EFI_INVALID_PARAMETER;
1826 }
1827
1828 if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {
1829 *PacketSizePtr = BUFFER_ALLOCATE_SIZE;
1830 }
1831
1832 if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {
1833 *PacketSizePtr = MAX_TFTP_PKT_SIZE;
1834 }
1835
1836 if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
1837 StatCode = TftpInfo (
1838 Private,
1839 BufferSizePtr,
1840 ServerIpPtr,
1841 TftpRequestPort,
1842 FilenamePtr,
1843 PacketSizePtr
1844 );
1845
1846 if (StatCode != EFI_SUCCESS) {
1847 DEBUG (
1848 (DEBUG_WARN,
1849 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1850 StatCode)
1851 );
1852 }
1853
1854 return StatCode;
1855 }
1856
1857 if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {
1858 if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {
1859 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #2"));
1860 return EFI_INVALID_PARAMETER;
1861 } else {
1862 StatCode = TftpInfo (
1863 Private,
1864 BufferSizePtr,
1865 ServerIpPtr,
1866 MtftpInfoPtr->SPort,
1867 FilenamePtr,
1868 PacketSizePtr
1869 );
1870
1871 gBS->Stall (10000);
1872
1873 if (StatCode != EFI_SUCCESS) {
1874 DEBUG (
1875 (DEBUG_WARN,
1876 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1877 StatCode)
1878 );
1879 }
1880
1881 return StatCode;
1882 }
1883 }
1884
1885 if (!BufferPtr && !DontUseBuffer) {
1886 //
1887 // if dontusebuffer is false and no buffer???
1888 //
1889 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #3"));
1890 //
1891 // DontUseBuffer can be true only for read_file operation
1892 //
1893 return EFI_INVALID_PARAMETER;
1894 }
1895
1896 if (DontUseBuffer) {
1897 Status = gBS->AllocatePool (
1898 EfiBootServicesData,
1899 BUFFER_ALLOCATE_SIZE,
1900 (VOID **) &BufferPtrLocal
1901 );
1902
1903 if (EFI_ERROR (Status) || BufferPtrLocal == NULL) {
1904 DEBUG ((DEBUG_NET, "\nPxeBcMtftp() Exit #4"));
1905 return EFI_OUT_OF_RESOURCES;
1906 }
1907
1908 BufferSizeLocal = BUFFER_ALLOCATE_SIZE;
1909 } else {
1910 if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {
1911 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #5"));
1912 return EFI_BAD_BUFFER_SIZE;
1913 }
1914
1915 BufferPtrLocal = BufferPtr;
1916 BufferSizeLocal = *BufferSizePtr;
1917 }
1918
1919 switch (Operation) {
1920 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
1921 if (FilenamePtr == NULL ||
1922 MtftpInfoPtr == NULL ||
1923 MtftpInfoPtr->MCastIp.Addr[0] == 0 ||
1924 MtftpInfoPtr->SPort == 0 ||
1925 MtftpInfoPtr->CPort == 0 ||
1926 MtftpInfoPtr->ListenTimeout == 0 ||
1927 MtftpInfoPtr->TransmitTimeout == 0
1928 ) {
1929 StatCode = EFI_INVALID_PARAMETER;
1930 break;
1931 }
1932 //
1933 // try MTFTP - if fails, drop into TFTP read
1934 //
1935 if ((StatCode = MtftpDownload (
1936 Private,
1937 &BufferSizeLocal,
1938 BufferPtrLocal,
1939 ServerIpPtr,
1940 FilenamePtr,
1941 MtftpInfoPtr,
1942 DontUseBuffer
1943 )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
1944 if (BufferSizePtr /* %% !DontUseBuffer */ ) {
1945 *BufferSizePtr = BufferSizeLocal;
1946 }
1947
1948 break;
1949 }
1950 //
1951 // go back to unicast
1952 //
1953 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1954 break;
1955 }
1956
1957 /* fall thru */
1958 case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
1959 if (FilenamePtr == NULL) {
1960 StatCode = EFI_INVALID_PARAMETER;
1961 break;
1962 }
1963
1964 StatCode = TftpDownload (
1965 Private,
1966 &BufferSizeLocal,
1967 BufferPtrLocal,
1968 ServerIpPtr,
1969 FilenamePtr,
1970 PacketSizePtr,
1971 TftpRequestPort,
1972 TFTP_RRQ,
1973 DontUseBuffer
1974 );
1975
1976 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
1977 if (BufferSizePtr /* !DontUseBuffer */ ) {
1978 *BufferSizePtr = BufferSizeLocal;
1979 }
1980 }
1981
1982 break;
1983
1984 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
1985 if (FilenamePtr == NULL || DontUseBuffer) {
1986 //
1987 // not a valid option
1988 //
1989 StatCode = EFI_INVALID_PARAMETER;
1990 break;
1991 }
1992
1993 StatCode = TftpUpload (
1994 Private,
1995 BufferSizePtr,
1996 BufferPtr,
1997 ServerIpPtr,
1998 FilenamePtr,
1999 PacketSizePtr,
2000 Overwrite
2001 );
2002
2003 if (StatCode != EFI_SUCCESS) {
2004 DEBUG (
2005 (DEBUG_WARN,
2006 "\nPxeBcMtftp() Exit #6 %xh (%r)",
2007 StatCode,
2008 StatCode)
2009 );
2010 }
2011
2012 return StatCode;
2013
2014 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
2015 if (FilenamePtr == NULL || DontUseBuffer) {
2016 //
2017 // not a valid option
2018 //
2019 StatCode = EFI_INVALID_PARAMETER;
2020 break;
2021 }
2022
2023 StatCode = TftpDownload (
2024 Private,
2025 BufferSizePtr,
2026 BufferPtr,
2027 ServerIpPtr,
2028 FilenamePtr,
2029 PacketSizePtr,
2030 TftpRequestPort,
2031 TFTP_DIR,
2032 DontUseBuffer
2033 );
2034
2035 if (StatCode != EFI_SUCCESS) {
2036 DEBUG (
2037 (DEBUG_WARN,
2038 "\nPxeBcMtftp() Exit #7 %xh (%r)",
2039 StatCode,
2040 StatCode)
2041 );
2042 }
2043
2044 return StatCode;
2045
2046 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
2047 if (DontUseBuffer) {
2048 StatCode = EFI_INVALID_PARAMETER;
2049 break;
2050 }
2051
2052 if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {
2053 DEBUG (
2054 (DEBUG_WARN,
2055 "\nPxeBcMtftp() Exit #9 %xh (%r)",
2056 EFI_INVALID_PARAMETER,
2057 EFI_INVALID_PARAMETER)
2058 );
2059
2060 return EFI_INVALID_PARAMETER;
2061 }
2062
2063 StatCode = TftpDownload (
2064 Private,
2065 BufferSizePtr,
2066 BufferPtr,
2067 ServerIpPtr,
2068 (UINT8 *) "/",
2069 PacketSizePtr,
2070 MtftpInfoPtr->SPort,
2071 TFTP_DIR,
2072 DontUseBuffer
2073 );
2074
2075 break;
2076
2077 default:
2078 StatCode = EFI_INVALID_PARAMETER;
2079 }
2080
2081 if (DontUseBuffer) {
2082 gBS->FreePool (BufferPtrLocal);
2083 }
2084
2085 if (StatCode != EFI_SUCCESS) {
2086 DEBUG (
2087 (DEBUG_WARN,
2088 "\nPxeBcMtftp() Exit #8 %xh (%r)",
2089 StatCode,
2090 StatCode)
2091 );
2092 }
2093
2094 gBS->Stall (10000);
2095
2096 return StatCode;
2097 }
2098
2099 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2100
2101 /**
2102
2103 @return * EFI_INVALID_PARAMETER
2104 @return * Status is also returned from PxeBcMtftp();
2105
2106 **/
2107 EFI_STATUS
2108 EFIAPI
2109 BcMtftp (
2110 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
2111 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
2112 IN OUT VOID *BufferPtr,
2113 IN BOOLEAN Overwrite,
2114 IN OUT UINT64 *BufferSizePtr,
2115 IN UINTN *BlockSizePtr OPTIONAL,
2116 IN EFI_IP_ADDRESS * ServerIpPtr,
2117 IN UINT8 *FilenamePtr,
2118 IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL,
2119 IN BOOLEAN DontUseBuffer
2120 )
2121 {
2122 EFI_PXE_BASE_CODE_IP_FILTER Filter;
2123 EFI_STATUS StatCode;
2124 PXE_BASECODE_DEVICE *Private;
2125
2126 //
2127 // Lock the instance data and make sure started
2128 //
2129 StatCode = EFI_SUCCESS;
2130
2131 if (This == NULL) {
2132 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
2133 return EFI_INVALID_PARAMETER;
2134 }
2135
2136 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2137
2138 if (Private == NULL) {
2139 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
2140 return EFI_INVALID_PARAMETER;
2141 }
2142
2143 if (!IS_INADDR_UNICAST (ServerIpPtr)) {
2144 //
2145 // The station IP is not a unicast address.
2146 //
2147 return EFI_INVALID_PARAMETER;
2148 }
2149
2150 EfiAcquireLock (&Private->Lock);
2151
2152 if (This->Mode == NULL || !This->Mode->Started) {
2153 DEBUG ((DEBUG_ERROR, "BC was not started."));
2154 EfiReleaseLock (&Private->Lock);
2155 return EFI_NOT_STARTED;
2156 }
2157 //
2158 // Issue BC command
2159 //
2160 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
2161 Filter.IpCnt = 0;
2162 Filter.reserved = 0;
2163
2164 DEBUG ((DEBUG_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr));
2165
2166 StatCode = PxeBcMtftp (
2167 Private,
2168 Operation,
2169 BufferSizePtr,
2170 BufferPtr,
2171 ServerIpPtr,
2172 FilenamePtr,
2173 BlockSizePtr,
2174 MtftpInfoPtr,
2175 Overwrite,
2176 DontUseBuffer
2177 );
2178
2179 //
2180 // restore to unicast
2181 //
2182 IpFilter (Private, &Filter);
2183
2184 //
2185 // Unlock the instance data
2186 //
2187 EfiReleaseLock (&Private->Lock);
2188 return StatCode;
2189 }
2190
2191 /* eof - PxeBcMtftp.c */