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