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