]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_mtftp.c
1. Sync the latest network stack. Add NetLibCreateIPv4DPathNode () in netlib library.
[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 = (UINTN) BufferSize;
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 Filter.IpList[0] = Private->EfiBc.Mode->StationIp;
1105 Filter.IpList[1] = MtftpInfoPtr->MCastIp;
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 #ifdef SpecialNowaitVersion
1131 #pragma message ("This is special version for MTFTP regression test")
1132 if (StartBlock || !LastBlock)
1133 #endif
1134 if (((Status = MtftpListen (
1135 Private,
1136 &BufferSize,
1137 BufferPtrLocal,
1138 ServerIpPtr,
1139 MtftpInfoPtr,
1140 &StartBlock,
1141 &NumMissed,
1142 TransTimeout,
1143 ListenTimeout,
1144 LastBlock,
1145 DontUseBuffer
1146 )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) {
1147 return Status;
1148 //
1149 // failed
1150 //
1151 }
1152 //
1153 // if none were received, start block is not reset
1154 //
1155 if (StartBlock == LastStartBlock) {
1156 UINT8 CompStat;
1157
1158 //
1159 // timed out with none received - try MTFTP open
1160 //
1161 if ((Status = MtftpOpen (
1162 Private,
1163 BufferSizePtr,
1164 BufferPtr,
1165 &Offset,
1166 ServerIpPtr,
1167 FilenamePtr,
1168 MtftpInfoPtr,
1169 &CompStat,
1170 DontUseBuffer
1171 )) != EFI_SUCCESS) {
1172 //
1173 // open failure - try TFTP
1174 //
1175 return Status;
1176 }
1177 //
1178 // return code EFI_SUCCESS
1179 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1180 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1181 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1182 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1183 //
1184 if (CompStat == (GOTUNI | GOTMULTI)) {
1185 //
1186 // finished - got it all
1187 //
1188 return Status;
1189 }
1190
1191 if (CompStat) {
1192 //
1193 // offset is two packet lengths
1194 //
1195 Offset <<= 1;
1196 //
1197 // last block received
1198 //
1199 LastStartBlock = 2;
1200 } else {
1201 Offset = 0;
1202 LastStartBlock = 0;
1203 }
1204
1205 ListenTimeout = TransTimeout;
1206 continue;
1207 }
1208 //
1209 // did we get the last block
1210 //
1211 if (Status == EFI_SUCCESS) {
1212 //
1213 // yes - set the file size if this was first time
1214 //
1215 if (!LastBlock) {
1216 *BufferSizePtr -= BufferSize;
1217 }
1218 //
1219 // if buffer was too small, finished
1220 //
1221 if (!DontUseBuffer) {
1222 return EFI_BUFFER_TOO_SMALL;
1223 }
1224 //
1225 // if we got them all, finished
1226 //
1227 if (!NumMissed && StartBlock == LastStartBlock + 1) {
1228 return Status;
1229 }
1230 //
1231 // did not get them all - set last block
1232 //
1233 LastBlock = (UINT16) (StartBlock - 1);
1234 }
1235 //
1236 // compute listen timeout
1237 //
1238 ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed));
1239
1240 //
1241 // reset
1242 //
1243 Offset = 0;
1244 LastStartBlock = 0;
1245 }
1246 }
1247
1248 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1249
1250 /**
1251
1252
1253 **/
1254 STATIC
1255 EFI_STATUS
1256 TftpInfo (
1257 PXE_BASECODE_DEVICE *Private,
1258 UINT64 *BufferSizePtr,
1259 EFI_IP_ADDRESS *ServerIpPtr,
1260 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
1261 UINT8 *FilenamePtr,
1262 UINTN *PacketSizePtr
1263 )
1264 {
1265 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1266 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1267 EFI_STATUS Status;
1268 UINT64 BlockNum;
1269 UINTN Offset;
1270 UINTN ReplyLen;
1271 UINT8 *Ptr;
1272
1273 union {
1274 struct Tftpv4Oack OAck2Ptr;
1275 struct Tftpv4Ack Ack2Ptr;
1276 struct Tftpv4Data Datastr;
1277 } u;
1278
1279 OurPort = 0;
1280 ServerReplyPort = 0;
1281 ReplyLen = sizeof (u.Datastr.Data);
1282
1283 //
1284 // send a write request with the blocksize option -
1285 // sets our IP and port - and receive reply - sets his port
1286 // will retry operation up to 3 times if no response,
1287 // and will retry without options on an error reply
1288 //
1289 if ((Status = TftpRwReqwResp (
1290 TFTP_RRQ,
1291 /* BIGBLKNUMOP | */BKSZOP | TSIZEOP,
1292 Private,
1293 &u,
1294 PacketSizePtr,
1295 &ReplyLen,
1296 u.Datastr.Data,
1297 ServerIpPtr,
1298 &SrvPort,
1299 &ServerReplyPort,
1300 &OurPort,
1301 FilenamePtr,
1302 REQ_RESP_TIMEOUT
1303 )) != EFI_SUCCESS) {
1304 DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #1"));
1305 return Status;
1306 }
1307 //
1308 // check for good OACK
1309 //
1310 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1311 //
1312 // now parse it for options
1313 // bigblk#
1314 //
1315 Ptr = FindOption (
1316 BigBlkNumOp,
1317 sizeof (BigBlkNumOp),
1318 u.OAck2Ptr.OpAck[0].Option,
1319 ReplyLen + sizeof (u.Ack2Ptr.BlockNum)
1320 );
1321
1322 if (Ptr != NULL) {
1323 if (AtoU (Ptr) == 8) {
1324 Private->BigBlkNumFlag = TRUE;
1325 } else {
1326 return EFI_PROTOCOL_ERROR;
1327 }
1328 }
1329 //
1330 // blksize
1331 //
1332 Ptr = FindOption (
1333 BlockSizeOp,
1334 sizeof (BlockSizeOp),
1335 u.OAck2Ptr.OpAck[0].Option,
1336 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
1337 );
1338
1339 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
1340
1341 //
1342 // tsize
1343 //
1344 Ptr = FindOption (
1345 TsizeOp,
1346 sizeof (TsizeOp),
1347 u.OAck2Ptr.OpAck[0].Option,
1348 ReplyLen
1349 );
1350
1351 if (Ptr != NULL) {
1352 *BufferSizePtr = AtoU64 (Ptr);
1353
1354 //
1355 // teminate session with error
1356 //
1357 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
1358
1359 return EFI_SUCCESS;
1360 }
1361
1362 Offset = 0;
1363 BlockNum = 0;
1364 } else {
1365 //
1366 // if MTFTP get filesize, return unsupported
1367 //
1368 if (SrvPort != TftpRequestPort) {
1369 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
1370 DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #3"));
1371 return EFI_UNSUPPORTED;
1372 }
1373
1374 Offset = ReplyLen;
1375 //
1376 // last block received
1377 //
1378 BlockNum = 1;
1379 }
1380 //
1381 // does not support the option - do a download with no buffer
1382 //
1383 *BufferSizePtr = 0;
1384
1385 Status = LockStepReceive (
1386 Private,
1387 (UINT16) ReplyLen,
1388 BufferSizePtr,
1389 Offset,
1390 (UINT8 *) &u,
1391 ServerIpPtr,
1392 &ServerReplyPort,
1393 &Private->EfiBc.Mode->StationIp,
1394 &OurPort,
1395 BlockNum,
1396 ACK_TIMEOUT,
1397 TRUE
1398 );
1399
1400 if (Status != EFI_SUCCESS) {
1401 DEBUG ((DEBUG_WARN, "\nTftpInfo() LockStepReceive() == %Xh", Status));
1402 }
1403
1404 if (Status != EFI_BUFFER_TOO_SMALL) {
1405 return Status;
1406 }
1407
1408 return EFI_SUCCESS;
1409 }
1410
1411 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1412
1413 /**
1414
1415
1416 **/
1417 STATIC
1418 EFI_STATUS
1419 TftpDownload (
1420 PXE_BASECODE_DEVICE *Private,
1421 UINT64 *BufferSizePtr,
1422 UINT8 *BufferPtr,
1423 EFI_IP_ADDRESS *ServerIpPtr,
1424 UINT8 *FilenamePtr,
1425 UINTN *PacketSizePtr,
1426 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
1427 UINT16 Req,
1428 IN BOOLEAN DontUseBuffer
1429 )
1430 {
1431 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1432 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1433 EFI_STATUS Status;
1434 UINT64 Offset;
1435 UINT64 BlockNum;
1436 UINTN ReplyLen;
1437 UINT8 *Ptr;
1438
1439 union {
1440 struct Tftpv4Ack Ack2Ptr;
1441 struct Tftpv4Oack OAck2Ptr;
1442 struct Tftpv4Data Data;
1443 struct Tftpv4Ack8 Ack8Ptr;
1444 struct Tftpv4Data8 Data8;
1445 } U;
1446
1447 OurPort = 0;
1448 ServerReplyPort = 0;
1449 ReplyLen = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr);
1450
1451 //
1452 // send a read request with the blocksize option - sets our IP and port
1453 // - and receive reply - sets his port will retry operation up to 3
1454 // times if no response, and will retry without options on an error
1455 // reply
1456 //
1457 if ((Status = TftpRwReqwResp (
1458 Req,
1459 /* BIGBLKNUMOP | */BKSZOP,
1460 Private,
1461 &U,
1462 PacketSizePtr,
1463 &ReplyLen,
1464 BufferPtr,
1465 ServerIpPtr,
1466 &SrvPort,
1467 &ServerReplyPort,
1468 &OurPort,
1469 FilenamePtr,
1470 REQ_RESP_TIMEOUT
1471 )) != EFI_SUCCESS) {
1472 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #1 %xh (%r)", Status, Status));
1473 return Status;
1474 }
1475 //
1476 // check for OACK
1477 //
1478 if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1479 //
1480 // get the OACK
1481 //
1482 CopyMem (U.Data.Data, BufferPtr, ReplyLen);
1483
1484 Ptr = FindOption (
1485 BigBlkNumOp,
1486 sizeof (BigBlkNumOp),
1487 U.OAck2Ptr.OpAck[0].Option,
1488 ReplyLen + sizeof (U.Ack2Ptr.BlockNum)
1489 );
1490
1491 if (Ptr != NULL) {
1492 if (AtoU (Ptr) == 8) {
1493 Private->BigBlkNumFlag = TRUE;
1494 } else {
1495 return EFI_PROTOCOL_ERROR;
1496 }
1497 }
1498 //
1499 // now parse it for blocksize option
1500 //
1501 Ptr = FindOption (
1502 BlockSizeOp,
1503 sizeof (BlockSizeOp),
1504 U.OAck2Ptr.OpAck[0].Option,
1505 ReplyLen += sizeof (U.Ack2Ptr.BlockNum)
1506 );
1507
1508 ReplyLen = (Ptr != NULL) ? AtoU (Ptr) : 512;
1509
1510 Offset = 0;
1511 //
1512 // last block received
1513 //
1514 BlockNum = 0;
1515 } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) {
1516 //
1517 // or data
1518 //
1519 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #2 %xh (%r)", Status, Status));
1520
1521 return EFI_PROTOCOL_ERROR;
1522 } else {
1523 //
1524 // got good data packet
1525 //
1526 Offset = ReplyLen;
1527 //
1528 // last block received
1529 //
1530 BlockNum = 1;
1531 }
1532
1533 if (PacketSizePtr != NULL) {
1534 *PacketSizePtr = ReplyLen;
1535 }
1536 //
1537 // routine to read rest of file after a successful open (TFTP or MTFTP)
1538 // sends ACK and gets next data packet until short packet arrives, then sends
1539 // ACK and (hopefully) times out
1540 // if first packet has been read, BufferPtr and BufferSize must reflect fact
1541 //
1542 Status = LockStepReceive (
1543 Private,
1544 ReplyLen,
1545 BufferSizePtr,
1546 Offset,
1547 BufferPtr,
1548 ServerIpPtr,
1549 &ServerReplyPort,
1550 &Private->EfiBc.Mode->StationIp,
1551 &OurPort,
1552 BlockNum,
1553 ACK_TIMEOUT,
1554 DontUseBuffer
1555 );
1556
1557 if (Status != EFI_SUCCESS) {
1558 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #3 %xh (%r)", Status, Status));
1559
1560 if (Status == EFI_BUFFER_TOO_SMALL) {
1561 Status = TftpInfo (
1562 Private,
1563 BufferSizePtr,
1564 ServerIpPtr,
1565 SrvPort,
1566 FilenamePtr,
1567 PacketSizePtr
1568 );
1569
1570 if (!EFI_ERROR (Status)) {
1571 Status = EFI_BUFFER_TOO_SMALL;
1572 }
1573 }
1574 }
1575
1576 return Status;
1577 }
1578
1579 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1580
1581 /**
1582
1583
1584 **/
1585 STATIC
1586 EFI_STATUS
1587 TftpUpload (
1588 PXE_BASECODE_DEVICE *Private,
1589 UINT64 *BufferSizePtr,
1590 VOID *BufferPtr,
1591 EFI_IP_ADDRESS *ServerIpPtr,
1592 UINT8 *FilenamePtr,
1593 UINTN *PacketSizePtr,
1594 BOOLEAN Overwrite
1595 )
1596 {
1597 struct Tftpv4Ack Header;
1598 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1599 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1600 EFI_STATUS Status;
1601 UINT64 BlockNum;
1602 UINT64 TransferSize;
1603 UINTN ReplyLen;
1604 UINTN TransferLen;
1605 UINT16 Options;
1606 UINT8 *Ptr;
1607
1608 union {
1609 struct Tftpv4Oack OAck2Ptr;
1610 struct Tftpv4Ack Ack2Ptr;
1611 struct Tftpv4Data Datastr;
1612 } u;
1613
1614 OurPort = 0;
1615 ServerReplyPort = 0;
1616 TransferSize = *BufferSizePtr;
1617 ReplyLen = sizeof (u.Datastr.Data);
1618 Options = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP);
1619
1620 //
1621 // send a write request with the blocksize option - sets our IP and port -
1622 // and receive reply - sets his port
1623 // will retry operation up to 3 times if no response, and will retry without
1624 // options on an error reply
1625 //
1626 if ((Status = TftpRwReqwResp (
1627 TFTP_WRQ,
1628 Options,
1629 Private,
1630 &u,
1631 PacketSizePtr,
1632 &ReplyLen,
1633 u.Datastr.Data,
1634 ServerIpPtr,
1635 &TftpRequestPort,
1636 &ServerReplyPort,
1637 &OurPort,
1638 FilenamePtr,
1639 REQ_RESP_TIMEOUT
1640 )) != EFI_SUCCESS) {
1641 return Status;
1642 }
1643 //
1644 // check for OACK
1645 //
1646 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1647 //
1648 // parse it for blocksize option
1649 //
1650 Ptr = FindOption (
1651 BlockSizeOp,
1652 sizeof (BlockSizeOp),
1653 u.OAck2Ptr.OpAck[0].Option,
1654 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
1655 );
1656 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
1657 }
1658 //
1659 // or ACK
1660 //
1661 else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) {
1662 //
1663 // option was not supported
1664 //
1665 *PacketSizePtr = 512;
1666 } else {
1667 return EFI_PROTOCOL_ERROR;
1668 }
1669 //
1670 // loop
1671 //
1672 Header.OpCode = HTONS (TFTP_DATA);
1673 BlockNum = 1;
1674 Header.BlockNum = HTONS (1);
1675
1676 do {
1677 UINTN HeaderSize;
1678 INTN Retries;
1679
1680 Retries = NUM_ACK_RETRIES;
1681 HeaderSize = sizeof (Header);
1682 TransferLen = (UINTN) (MIN (*PacketSizePtr, TransferSize));
1683
1684 //
1685 // write a data packet and get an ack
1686 //
1687 do {
1688 //
1689 // write
1690 //
1691 if ((Status = UdpWrite (
1692 Private,
1693 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
1694 ServerIpPtr,
1695 &ServerReplyPort,
1696 0,
1697 0,
1698 &OurPort,
1699 &HeaderSize,
1700 &Header,
1701 &TransferLen,
1702 BufferPtr
1703 )) != EFI_SUCCESS) {
1704 return Status;
1705 }
1706 //
1707 // read reply
1708 //
1709 ReplyLen = sizeof (u.Datastr.Data);
1710
1711 if ((Status = TftpUdpRead (
1712 Private,
1713 0,
1714 &u,
1715 &ReplyLen,
1716 u.Datastr.Data,
1717 ServerIpPtr,
1718 &ServerReplyPort,
1719 0,
1720 &OurPort,
1721 ACK_TIMEOUT
1722 )) == EFI_SUCCESS) {
1723 //
1724 // check for ACK for this data packet
1725 //
1726 if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) {
1727 return EFI_PROTOCOL_ERROR;
1728 }
1729
1730 if (u.Ack2Ptr.BlockNum != Header.BlockNum) {
1731 //
1732 // not for this packet - continue
1733 //
1734 Status = EFI_TIMEOUT;
1735 }
1736 }
1737 } while (Status == EFI_TIMEOUT && --Retries);
1738
1739 if (Status != EFI_SUCCESS) {
1740 return Status;
1741 }
1742
1743 BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen);
1744 TransferSize -= TransferLen;
1745 ++BlockNum;
1746 Header.BlockNum = HTONS ((UINT16) BlockNum);
1747 } while (TransferLen == *PacketSizePtr);
1748
1749 return EFI_SUCCESS;
1750 }
1751
1752 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1753
1754 /**
1755
1756 @return * EFI_INVALID_PARAMETER
1757 @return * EFI_OUT_OF_RESOURCES
1758 @return * EFI_BAD_BUFFER_SIZE
1759 @return * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
1760 @return * TftpDownload() and TftpUpload().
1761
1762 **/
1763 EFI_STATUS
1764 PxeBcMtftp (
1765 PXE_BASECODE_DEVICE *Private,
1766 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
1767 UINT64 *BufferSizePtr,
1768 VOID *BufferPtr,
1769 EFI_IP_ADDRESS *ServerIpPtr,
1770 UINT8 *FilenamePtr,
1771 UINTN *PacketSizePtr,
1772 IN EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, OPTIONAL
1773 IN BOOLEAN Overwrite,
1774 IN BOOLEAN DontUseBuffer
1775 )
1776 {
1777 EFI_PXE_BASE_CODE_IP_FILTER Filter;
1778 EFI_STATUS StatCode;
1779 EFI_STATUS Status;
1780 UINT64 BufferSizeLocal;
1781 UINTN PacketSize;
1782 UINT8 *BufferPtrLocal;
1783
1784 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
1785 Filter.IpCnt = 0;
1786 Filter.reserved = 0;
1787
1788 /* No error has occurred, yet. */
1789 Private->EfiBc.Mode->TftpErrorReceived = FALSE;
1790
1791 /* We must at least have an MTFTP server IP address and
1792 * a pointer to the buffer size.
1793 */
1794 if (!ServerIpPtr || !BufferSizePtr) {
1795 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #1"));
1796
1797 return EFI_INVALID_PARAMETER;
1798 }
1799
1800 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;
1801
1802 //
1803 // make sure filter set to unicast at start
1804 //
1805 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1806 DEBUG (
1807 (DEBUG_NET,
1808 "\nPxeBcMtftp() Exit IpFilter() == %Xh",
1809 StatCode)
1810 );
1811
1812 return StatCode;
1813 }
1814 //
1815 // set unset parms to default values
1816 //
1817 if (!PacketSizePtr) {
1818 *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;
1819 }
1820
1821 if (*PacketSizePtr > *BufferSizePtr) {
1822 *PacketSizePtr = (UINTN) *BufferSizePtr;
1823 }
1824
1825 if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {
1826 *PacketSizePtr = MIN_TFTP_PKT_SIZE;
1827 return EFI_INVALID_PARAMETER;
1828 }
1829
1830 if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {
1831 *PacketSizePtr = BUFFER_ALLOCATE_SIZE;
1832 }
1833
1834 if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {
1835 *PacketSizePtr = MAX_TFTP_PKT_SIZE;
1836 }
1837
1838 if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
1839 StatCode = TftpInfo (
1840 Private,
1841 BufferSizePtr,
1842 ServerIpPtr,
1843 TftpRequestPort,
1844 FilenamePtr,
1845 PacketSizePtr
1846 );
1847
1848 if (StatCode != EFI_SUCCESS) {
1849 DEBUG (
1850 (DEBUG_WARN,
1851 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1852 StatCode)
1853 );
1854 }
1855
1856 return StatCode;
1857 }
1858
1859 if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {
1860 if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {
1861 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #2"));
1862 return EFI_INVALID_PARAMETER;
1863 } else {
1864 StatCode = TftpInfo (
1865 Private,
1866 BufferSizePtr,
1867 ServerIpPtr,
1868 MtftpInfoPtr->SPort,
1869 FilenamePtr,
1870 PacketSizePtr
1871 );
1872
1873 gBS->Stall (10000);
1874
1875 if (StatCode != EFI_SUCCESS) {
1876 DEBUG (
1877 (DEBUG_WARN,
1878 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
1879 StatCode)
1880 );
1881 }
1882
1883 return StatCode;
1884 }
1885 }
1886
1887 if (!BufferPtr && !DontUseBuffer) {
1888 //
1889 // if dontusebuffer is false and no buffer???
1890 //
1891 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #3"));
1892 //
1893 // DontUseBuffer can be true only for read_file operation
1894 //
1895 return EFI_INVALID_PARAMETER;
1896 }
1897
1898 if (DontUseBuffer) {
1899 Status = gBS->AllocatePool (
1900 EfiBootServicesData,
1901 BUFFER_ALLOCATE_SIZE,
1902 (VOID **) &BufferPtrLocal
1903 );
1904
1905 if (EFI_ERROR (Status) || BufferPtrLocal == NULL) {
1906 DEBUG ((DEBUG_NET, "\nPxeBcMtftp() Exit #4"));
1907 return EFI_OUT_OF_RESOURCES;
1908 }
1909
1910 BufferSizeLocal = BUFFER_ALLOCATE_SIZE;
1911 } else {
1912 if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {
1913 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #5"));
1914 return EFI_BAD_BUFFER_SIZE;
1915 }
1916
1917 BufferPtrLocal = BufferPtr;
1918 BufferSizeLocal = *BufferSizePtr;
1919 }
1920
1921 switch (Operation) {
1922 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
1923 if (FilenamePtr == NULL ||
1924 MtftpInfoPtr == NULL ||
1925 MtftpInfoPtr->MCastIp.Addr[0] == 0 ||
1926 MtftpInfoPtr->SPort == 0 ||
1927 MtftpInfoPtr->CPort == 0 ||
1928 MtftpInfoPtr->ListenTimeout == 0 ||
1929 MtftpInfoPtr->TransmitTimeout == 0
1930 ) {
1931 StatCode = EFI_INVALID_PARAMETER;
1932 break;
1933 }
1934 //
1935 // try MTFTP - if fails, drop into TFTP read
1936 //
1937 if ((StatCode = MtftpDownload (
1938 Private,
1939 &BufferSizeLocal,
1940 BufferPtrLocal,
1941 ServerIpPtr,
1942 FilenamePtr,
1943 MtftpInfoPtr,
1944 DontUseBuffer
1945 )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
1946 if (BufferSizePtr /* %% !DontUseBuffer */ ) {
1947 *BufferSizePtr = BufferSizeLocal;
1948 }
1949
1950 break;
1951 }
1952 //
1953 // go back to unicast
1954 //
1955 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1956 break;
1957 }
1958
1959 /* fall thru */
1960 case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
1961 if (FilenamePtr == NULL) {
1962 StatCode = EFI_INVALID_PARAMETER;
1963 break;
1964 }
1965
1966 StatCode = TftpDownload (
1967 Private,
1968 &BufferSizeLocal,
1969 BufferPtrLocal,
1970 ServerIpPtr,
1971 FilenamePtr,
1972 PacketSizePtr,
1973 TftpRequestPort,
1974 TFTP_RRQ,
1975 DontUseBuffer
1976 );
1977
1978 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
1979 if (BufferSizePtr /* !DontUseBuffer */ ) {
1980 *BufferSizePtr = BufferSizeLocal;
1981 }
1982 }
1983
1984 break;
1985
1986 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
1987 if (FilenamePtr == NULL || DontUseBuffer) {
1988 //
1989 // not a valid option
1990 //
1991 StatCode = EFI_INVALID_PARAMETER;
1992 break;
1993 }
1994
1995 StatCode = TftpUpload (
1996 Private,
1997 BufferSizePtr,
1998 BufferPtr,
1999 ServerIpPtr,
2000 FilenamePtr,
2001 PacketSizePtr,
2002 Overwrite
2003 );
2004
2005 if (StatCode != EFI_SUCCESS) {
2006 DEBUG (
2007 (DEBUG_WARN,
2008 "\nPxeBcMtftp() Exit #6 %xh (%r)",
2009 StatCode,
2010 StatCode)
2011 );
2012 }
2013
2014 return StatCode;
2015
2016 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
2017 if (FilenamePtr == NULL || DontUseBuffer) {
2018 //
2019 // not a valid option
2020 //
2021 StatCode = EFI_INVALID_PARAMETER;
2022 break;
2023 }
2024
2025 StatCode = TftpDownload (
2026 Private,
2027 BufferSizePtr,
2028 BufferPtr,
2029 ServerIpPtr,
2030 FilenamePtr,
2031 PacketSizePtr,
2032 TftpRequestPort,
2033 TFTP_DIR,
2034 DontUseBuffer
2035 );
2036
2037 if (StatCode != EFI_SUCCESS) {
2038 DEBUG (
2039 (DEBUG_WARN,
2040 "\nPxeBcMtftp() Exit #7 %xh (%r)",
2041 StatCode,
2042 StatCode)
2043 );
2044 }
2045
2046 return StatCode;
2047
2048 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
2049 if (DontUseBuffer) {
2050 StatCode = EFI_INVALID_PARAMETER;
2051 break;
2052 }
2053
2054 if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {
2055 DEBUG (
2056 (DEBUG_WARN,
2057 "\nPxeBcMtftp() Exit #9 %xh (%r)",
2058 EFI_INVALID_PARAMETER,
2059 EFI_INVALID_PARAMETER)
2060 );
2061
2062 return EFI_INVALID_PARAMETER;
2063 }
2064
2065 StatCode = TftpDownload (
2066 Private,
2067 BufferSizePtr,
2068 BufferPtr,
2069 ServerIpPtr,
2070 (UINT8 *) "/",
2071 PacketSizePtr,
2072 MtftpInfoPtr->SPort,
2073 TFTP_DIR,
2074 DontUseBuffer
2075 );
2076
2077 break;
2078
2079 default:
2080 StatCode = EFI_INVALID_PARAMETER;
2081 }
2082
2083 if (DontUseBuffer) {
2084 gBS->FreePool (BufferPtrLocal);
2085 }
2086
2087 if (StatCode != EFI_SUCCESS) {
2088 DEBUG (
2089 (DEBUG_WARN,
2090 "\nPxeBcMtftp() Exit #8 %xh (%r)",
2091 StatCode,
2092 StatCode)
2093 );
2094 }
2095
2096 gBS->Stall (10000);
2097
2098 return StatCode;
2099 }
2100
2101 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2102
2103 /**
2104
2105 @return * EFI_INVALID_PARAMETER
2106 @return * Status is also returned from PxeBcMtftp();
2107
2108 **/
2109 EFI_STATUS
2110 EFIAPI
2111 BcMtftp (
2112 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
2113 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
2114 IN OUT VOID *BufferPtr,
2115 IN BOOLEAN Overwrite,
2116 IN OUT UINT64 *BufferSizePtr,
2117 IN UINTN *BlockSizePtr OPTIONAL,
2118 IN EFI_IP_ADDRESS * ServerIpPtr,
2119 IN UINT8 *FilenamePtr,
2120 IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL,
2121 IN BOOLEAN DontUseBuffer
2122 )
2123 {
2124 EFI_PXE_BASE_CODE_IP_FILTER Filter;
2125 EFI_STATUS StatCode;
2126 PXE_BASECODE_DEVICE *Private;
2127
2128 //
2129 // Lock the instance data and make sure started
2130 //
2131 StatCode = EFI_SUCCESS;
2132
2133 if (This == NULL) {
2134 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
2135 return EFI_INVALID_PARAMETER;
2136 }
2137
2138 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2139
2140 if (Private == NULL) {
2141 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
2142 return EFI_INVALID_PARAMETER;
2143 }
2144
2145 if (!IS_INADDR_UNICAST (ServerIpPtr)) {
2146 //
2147 // The station IP is not a unicast address.
2148 //
2149 return EFI_INVALID_PARAMETER;
2150 }
2151
2152 EfiAcquireLock (&Private->Lock);
2153
2154 if (This->Mode == NULL || !This->Mode->Started) {
2155 DEBUG ((DEBUG_ERROR, "BC was not started."));
2156 EfiReleaseLock (&Private->Lock);
2157 return EFI_NOT_STARTED;
2158 }
2159 //
2160 // Issue BC command
2161 //
2162 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
2163 Filter.IpCnt = 0;
2164 Filter.reserved = 0;
2165
2166 DEBUG ((DEBUG_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr));
2167
2168 StatCode = PxeBcMtftp (
2169 Private,
2170 Operation,
2171 BufferSizePtr,
2172 BufferPtr,
2173 ServerIpPtr,
2174 FilenamePtr,
2175 BlockSizePtr,
2176 MtftpInfoPtr,
2177 Overwrite,
2178 DontUseBuffer
2179 );
2180
2181 //
2182 // restore to unicast
2183 //
2184 IpFilter (Private, &Filter);
2185
2186 //
2187 // Unlock the instance data
2188 //
2189 EfiReleaseLock (&Private->Lock);
2190 return StatCode;
2191 }
2192
2193 /* eof - PxeBcMtftp.c */