]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c
Add some definitions for efi event in Uefi/UefiSpec.h to follow spec.
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_bc_mtftp.c
1 /*++
2
3 Copyright (c) 2006 - 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 // 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 EVT_TIMER,
121 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 if (((Status = MtftpListen (
1260 Private,
1261 &BufferSize,
1262 BufferPtrLocal,
1263 ServerIpPtr,
1264 MtftpInfoPtr,
1265 &StartBlock,
1266 &NumMissed,
1267 TransTimeout,
1268 ListenTimeout,
1269 LastBlock,
1270 DontUseBuffer
1271 )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) {
1272 return Status;
1273 //
1274 // failed
1275 //
1276 }
1277 //
1278 // if none were received, start block is not reset
1279 //
1280 if (StartBlock == LastStartBlock) {
1281 UINT8 CompStat;
1282
1283 //
1284 // timed out with none received - try MTFTP open
1285 //
1286 if ((Status = MtftpOpen (
1287 Private,
1288 BufferSizePtr,
1289 BufferPtr,
1290 &Offset,
1291 ServerIpPtr,
1292 FilenamePtr,
1293 MtftpInfoPtr,
1294 &CompStat,
1295 DontUseBuffer
1296 )) != EFI_SUCCESS) {
1297 //
1298 // open failure - try TFTP
1299 //
1300 return Status;
1301 }
1302 //
1303 // return code EFI_SUCCESS
1304 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
1305 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
1306 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
1307 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
1308 //
1309 if (CompStat == (GOTUNI | GOTMULTI)) {
1310 //
1311 // finished - got it all
1312 //
1313 return Status;
1314 }
1315
1316 if (CompStat) {
1317 //
1318 // offset is two packet lengths
1319 //
1320 Offset <<= 1;
1321 //
1322 // last block received
1323 //
1324 LastStartBlock = 2;
1325 } else {
1326 Offset = 0;
1327 LastStartBlock = 0;
1328 }
1329
1330 ListenTimeout = TransTimeout;
1331 continue;
1332 }
1333 //
1334 // did we get the last block
1335 //
1336 if (Status == EFI_SUCCESS) {
1337 //
1338 // yes - set the file size if this was first time
1339 //
1340 if (!LastBlock) {
1341 *BufferSizePtr -= BufferSize;
1342 }
1343 //
1344 // if buffer was too small, finished
1345 //
1346 if (!DontUseBuffer) {
1347 return EFI_BUFFER_TOO_SMALL;
1348 }
1349 //
1350 // if we got them all, finished
1351 //
1352 if (!NumMissed && StartBlock == LastStartBlock + 1) {
1353 return Status;
1354 }
1355 //
1356 // did not get them all - set last block
1357 //
1358 LastBlock = (UINT16) (StartBlock - 1);
1359 }
1360 //
1361 // compute listen timeout
1362 //
1363 ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed));
1364
1365 //
1366 // reset
1367 //
1368 Offset = 0;
1369 LastStartBlock = 0;
1370 }
1371 }
1372
1373 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1374 STATIC
1375 EFI_STATUS
1376 TftpInfo (
1377 PXE_BASECODE_DEVICE *Private,
1378 UINT64 *BufferSizePtr,
1379 EFI_IP_ADDRESS *ServerIpPtr,
1380 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
1381 UINT8 *FilenamePtr,
1382 UINTN *PacketSizePtr
1383 )
1384 /*++
1385 Routine description:
1386 // TFTP info request routine
1387 // send read request with block size and transfer size options
1388 // get reply
1389 // send error to terminate session
1390 // if OACK received, set info
1391
1392 Parameters:
1393 Private :=
1394 BufferSizePtr :=
1395 ServerIpPtr :=
1396 SrvPort :=
1397 FilenamePtr :=
1398 PacketSizePtr :=
1399
1400 Returns:
1401 --*/
1402 {
1403 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1404 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1405 EFI_STATUS Status;
1406 UINT64 BlockNum;
1407 UINTN Offset;
1408 UINTN ReplyLen;
1409 UINT8 *Ptr;
1410
1411 union {
1412 struct Tftpv4Oack OAck2Ptr;
1413 struct Tftpv4Ack Ack2Ptr;
1414 struct Tftpv4Data Datastr;
1415 } u;
1416
1417 OurPort = 0;
1418 ServerReplyPort = 0;
1419 ReplyLen = sizeof (u.Datastr.Data);
1420
1421 //
1422 // send a write request with the blocksize option -
1423 // sets our IP and port - and receive reply - sets his port
1424 // will retry operation up to 3 times if no response,
1425 // and will retry without options on an error reply
1426 //
1427 if ((Status = TftpRwReqwResp (
1428 TFTP_RRQ,
1429 /* BIGBLKNUMOP | */BKSZOP | TSIZEOP,
1430 Private,
1431 &u,
1432 PacketSizePtr,
1433 &ReplyLen,
1434 u.Datastr.Data,
1435 ServerIpPtr,
1436 &SrvPort,
1437 &ServerReplyPort,
1438 &OurPort,
1439 FilenamePtr,
1440 REQ_RESP_TIMEOUT
1441 )) != EFI_SUCCESS) {
1442 DEBUG ((EFI_D_WARN, "\nTftpInfo() Exit #1"));
1443 return Status;
1444 }
1445 //
1446 // check for good OACK
1447 //
1448 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1449 //
1450 // now parse it for options
1451 // bigblk#
1452 //
1453 Ptr = FindOption (
1454 BigBlkNumOp,
1455 sizeof (BigBlkNumOp),
1456 u.OAck2Ptr.OpAck[0].Option,
1457 ReplyLen + sizeof (u.Ack2Ptr.BlockNum)
1458 );
1459
1460 if (Ptr != NULL) {
1461 if (AtoU (Ptr) == 8) {
1462 Private->BigBlkNumFlag = TRUE;
1463 } else {
1464 return EFI_PROTOCOL_ERROR;
1465 }
1466 }
1467 //
1468 // blksize
1469 //
1470 Ptr = FindOption (
1471 BlockSizeOp,
1472 sizeof (BlockSizeOp),
1473 u.OAck2Ptr.OpAck[0].Option,
1474 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
1475 );
1476
1477 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
1478
1479 //
1480 // tsize
1481 //
1482 Ptr = FindOption (
1483 TsizeOp,
1484 sizeof (TsizeOp),
1485 u.OAck2Ptr.OpAck[0].Option,
1486 ReplyLen
1487 );
1488
1489 if (Ptr != NULL) {
1490 *BufferSizePtr = AtoU64 (Ptr);
1491
1492 //
1493 // teminate session with error
1494 //
1495 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
1496
1497 return EFI_SUCCESS;
1498 }
1499
1500 Offset = 0;
1501 BlockNum = 0;
1502 } else {
1503 //
1504 // if MTFTP get filesize, return unsupported
1505 //
1506 if (SrvPort != TftpRequestPort) {
1507 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
1508 DEBUG ((EFI_D_WARN, "\nTftpInfo() Exit #3"));
1509 return EFI_UNSUPPORTED;
1510 }
1511
1512 Offset = ReplyLen;
1513 //
1514 // last block received
1515 //
1516 BlockNum = 1;
1517 }
1518 //
1519 // does not support the option - do a download with no buffer
1520 //
1521 *BufferSizePtr = 0;
1522
1523 Status = LockStepReceive (
1524 Private,
1525 (UINT16) ReplyLen,
1526 BufferSizePtr,
1527 Offset,
1528 (UINT8 *) &u,
1529 ServerIpPtr,
1530 &ServerReplyPort,
1531 &Private->EfiBc.Mode->StationIp,
1532 &OurPort,
1533 BlockNum,
1534 ACK_TIMEOUT,
1535 TRUE
1536 );
1537
1538 if (Status != EFI_SUCCESS) {
1539 DEBUG ((EFI_D_WARN, "\nTftpInfo() LockStepReceive() == %Xh", Status));
1540 }
1541
1542 if (Status != EFI_BUFFER_TOO_SMALL) {
1543 return Status;
1544 }
1545
1546 return EFI_SUCCESS;
1547 }
1548
1549 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1550 STATIC
1551 EFI_STATUS
1552 TftpDownload (
1553 PXE_BASECODE_DEVICE *Private,
1554 UINT64 *BufferSizePtr,
1555 UINT8 *BufferPtr,
1556 EFI_IP_ADDRESS *ServerIpPtr,
1557 UINT8 *FilenamePtr,
1558 UINTN *PacketSizePtr,
1559 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
1560 UINT16 Req,
1561 IN BOOLEAN DontUseBuffer
1562 )
1563 /*++
1564 Routine description:
1565 // tftp read session
1566 // send read request
1567 // [get OACK
1568 // send ACK]
1569 // loop
1570 // get data
1571 // send ACK
1572 // while data size is max
1573
1574 Parameters:
1575 Private :=
1576 BufferSizePtr :=
1577 BufferPtr :=
1578 ServerIpPtr :=
1579 FilenamePtr :=
1580 PacketSizePtr :=
1581 SrvPort :=
1582 Req :=
1583 DontUseBuffer :=
1584
1585 Returns:
1586 --*/
1587 {
1588 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1589 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1590 EFI_STATUS Status;
1591 UINT64 Offset;
1592 UINT64 BlockNum;
1593 UINTN ReplyLen;
1594 UINT8 *Ptr;
1595
1596 union {
1597 struct Tftpv4Ack Ack2Ptr;
1598 struct Tftpv4Oack OAck2Ptr;
1599 struct Tftpv4Data Data;
1600 struct Tftpv4Ack8 Ack8Ptr;
1601 struct Tftpv4Data8 Data8;
1602 } U;
1603
1604 OurPort = 0;
1605 ServerReplyPort = 0;
1606 ReplyLen = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr);
1607
1608 //
1609 // send a read request with the blocksize option - sets our IP and port
1610 // - and receive reply - sets his port will retry operation up to 3
1611 // times if no response, and will retry without options on an error
1612 // reply
1613 //
1614 if ((Status = TftpRwReqwResp (
1615 Req,
1616 /* BIGBLKNUMOP | */BKSZOP,
1617 Private,
1618 &U,
1619 PacketSizePtr,
1620 &ReplyLen,
1621 BufferPtr,
1622 ServerIpPtr,
1623 &SrvPort,
1624 &ServerReplyPort,
1625 &OurPort,
1626 FilenamePtr,
1627 REQ_RESP_TIMEOUT
1628 )) != EFI_SUCCESS) {
1629 DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #1 %xh (%r)", Status, Status));
1630 return Status;
1631 }
1632 //
1633 // check for OACK
1634 //
1635 if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1636 //
1637 // get the OACK
1638 //
1639 CopyMem (U.Data.Data, BufferPtr, ReplyLen);
1640
1641 Ptr = FindOption (
1642 BigBlkNumOp,
1643 sizeof (BigBlkNumOp),
1644 U.OAck2Ptr.OpAck[0].Option,
1645 ReplyLen + sizeof (U.Ack2Ptr.BlockNum)
1646 );
1647
1648 if (Ptr != NULL) {
1649 if (AtoU (Ptr) == 8) {
1650 Private->BigBlkNumFlag = TRUE;
1651 } else {
1652 return EFI_PROTOCOL_ERROR;
1653 }
1654 }
1655 //
1656 // now parse it for blocksize option
1657 //
1658 Ptr = FindOption (
1659 BlockSizeOp,
1660 sizeof (BlockSizeOp),
1661 U.OAck2Ptr.OpAck[0].Option,
1662 ReplyLen += sizeof (U.Ack2Ptr.BlockNum)
1663 );
1664
1665 ReplyLen = (Ptr != NULL) ? AtoU (Ptr) : 512;
1666
1667 Offset = 0;
1668 //
1669 // last block received
1670 //
1671 BlockNum = 0;
1672 } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) {
1673 //
1674 // or data
1675 //
1676 DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #2 %xh (%r)", Status, Status));
1677
1678 return EFI_PROTOCOL_ERROR;
1679 } else {
1680 //
1681 // got good data packet
1682 //
1683 Offset = ReplyLen;
1684 //
1685 // last block received
1686 //
1687 BlockNum = 1;
1688 }
1689
1690 if (PacketSizePtr != NULL) {
1691 *PacketSizePtr = ReplyLen;
1692 }
1693 //
1694 // routine to read rest of file after a successful open (TFTP or MTFTP)
1695 // sends ACK and gets next data packet until short packet arrives, then sends
1696 // ACK and (hopefully) times out
1697 // if first packet has been read, BufferPtr and BufferSize must reflect fact
1698 //
1699 Status = LockStepReceive (
1700 Private,
1701 ReplyLen,
1702 BufferSizePtr,
1703 Offset,
1704 BufferPtr,
1705 ServerIpPtr,
1706 &ServerReplyPort,
1707 &Private->EfiBc.Mode->StationIp,
1708 &OurPort,
1709 BlockNum,
1710 ACK_TIMEOUT,
1711 DontUseBuffer
1712 );
1713
1714 if (Status != EFI_SUCCESS) {
1715 DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #3 %xh (%r)", Status, Status));
1716
1717 if (Status == EFI_BUFFER_TOO_SMALL) {
1718 Status = TftpInfo (
1719 Private,
1720 BufferSizePtr,
1721 ServerIpPtr,
1722 SrvPort,
1723 FilenamePtr,
1724 PacketSizePtr
1725 );
1726
1727 if (!EFI_ERROR (Status)) {
1728 Status = EFI_BUFFER_TOO_SMALL;
1729 }
1730 }
1731 }
1732
1733 return Status;
1734 }
1735
1736 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1737 STATIC
1738 EFI_STATUS
1739 TftpUpload (
1740 PXE_BASECODE_DEVICE *Private,
1741 UINT64 *BufferSizePtr,
1742 VOID *BufferPtr,
1743 EFI_IP_ADDRESS *ServerIpPtr,
1744 UINT8 *FilenamePtr,
1745 UINTN *PacketSizePtr,
1746 BOOLEAN Overwrite
1747 )
1748 /*++
1749 Routine description:
1750 // tftp write session
1751 // send write request
1752 // get OACK or ACK
1753 // loop
1754 // send min (rest of data, max data packet)
1755 // get ACK
1756 // while data size is max
1757
1758 Parameters:
1759 Private :=
1760 BufferSizePtr :=
1761 BufferPtr :=
1762 ServerIpPtr :=
1763 FilenamePtr :=
1764 PacketSizePtr :=
1765 Overwrite :=
1766
1767 Returns:
1768 --*/
1769 {
1770 struct Tftpv4Ack Header;
1771 EFI_PXE_BASE_CODE_UDP_PORT OurPort;
1772 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
1773 EFI_STATUS Status;
1774 UINT64 BlockNum;
1775 UINT64 TransferSize;
1776 UINTN ReplyLen;
1777 UINTN TransferLen;
1778 UINT16 Options;
1779 UINT8 *Ptr;
1780
1781 union {
1782 struct Tftpv4Oack OAck2Ptr;
1783 struct Tftpv4Ack Ack2Ptr;
1784 struct Tftpv4Data Datastr;
1785 } u;
1786
1787 OurPort = 0;
1788 ServerReplyPort = 0;
1789 TransferSize = *BufferSizePtr;
1790 ReplyLen = sizeof (u.Datastr.Data);
1791 Options = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP);
1792
1793 //
1794 // send a write request with the blocksize option - sets our IP and port -
1795 // and receive reply - sets his port
1796 // will retry operation up to 3 times if no response, and will retry without
1797 // options on an error reply
1798 //
1799 if ((Status = TftpRwReqwResp (
1800 TFTP_WRQ,
1801 Options,
1802 Private,
1803 &u,
1804 PacketSizePtr,
1805 &ReplyLen,
1806 u.Datastr.Data,
1807 ServerIpPtr,
1808 &TftpRequestPort,
1809 &ServerReplyPort,
1810 &OurPort,
1811 FilenamePtr,
1812 REQ_RESP_TIMEOUT
1813 )) != EFI_SUCCESS) {
1814 return Status;
1815 }
1816 //
1817 // check for OACK
1818 //
1819 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
1820 //
1821 // parse it for blocksize option
1822 //
1823 Ptr = FindOption (
1824 BlockSizeOp,
1825 sizeof (BlockSizeOp),
1826 u.OAck2Ptr.OpAck[0].Option,
1827 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
1828 );
1829 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
1830 }
1831 //
1832 // or ACK
1833 //
1834 else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) {
1835 //
1836 // option was not supported
1837 //
1838 *PacketSizePtr = 512;
1839 } else {
1840 return EFI_PROTOCOL_ERROR;
1841 }
1842 //
1843 // loop
1844 //
1845 Header.OpCode = HTONS (TFTP_DATA);
1846 BlockNum = 1;
1847 Header.BlockNum = HTONS (1);
1848
1849 do {
1850 UINTN HeaderSize;
1851 INTN Retries;
1852
1853 Retries = NUM_ACK_RETRIES;
1854 HeaderSize = sizeof (Header);
1855 TransferLen = (UINTN) (EFI_MIN (*PacketSizePtr, TransferSize));
1856
1857 //
1858 // write a data packet and get an ack
1859 //
1860 do {
1861 //
1862 // write
1863 //
1864 if ((Status = UdpWrite (
1865 Private,
1866 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
1867 ServerIpPtr,
1868 &ServerReplyPort,
1869 0,
1870 0,
1871 &OurPort,
1872 &HeaderSize,
1873 &Header,
1874 &TransferLen,
1875 BufferPtr
1876 )) != EFI_SUCCESS) {
1877 return Status;
1878 }
1879 //
1880 // read reply
1881 //
1882 ReplyLen = sizeof (u.Datastr.Data);
1883
1884 if ((Status = TftpUdpRead (
1885 Private,
1886 0,
1887 &u,
1888 &ReplyLen,
1889 u.Datastr.Data,
1890 ServerIpPtr,
1891 &ServerReplyPort,
1892 0,
1893 &OurPort,
1894 ACK_TIMEOUT
1895 )) == EFI_SUCCESS) {
1896 //
1897 // check for ACK for this data packet
1898 //
1899 if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) {
1900 return EFI_PROTOCOL_ERROR;
1901 }
1902
1903 if (u.Ack2Ptr.BlockNum != Header.BlockNum) {
1904 //
1905 // not for this packet - continue
1906 //
1907 Status = EFI_TIMEOUT;
1908 }
1909 }
1910 } while (Status == EFI_TIMEOUT && --Retries);
1911
1912 if (Status != EFI_SUCCESS) {
1913 return Status;
1914 }
1915
1916 BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen);
1917 TransferSize -= TransferLen;
1918 ++BlockNum;
1919 Header.BlockNum = HTONS ((UINT16) BlockNum);
1920 } while (TransferLen == *PacketSizePtr);
1921
1922 return EFI_SUCCESS;
1923 }
1924
1925 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1926 STATIC
1927 EFI_STATUS
1928 PxeBcMtftp (
1929 PXE_BASECODE_DEVICE *Private,
1930 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
1931 UINT64 *BufferSizePtr,
1932 VOID *BufferPtr,
1933 EFI_IP_ADDRESS *ServerIpPtr,
1934 UINT8 *FilenamePtr,
1935 UINTN *PacketSizePtr,
1936 IN EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, OPTIONAL
1937 IN BOOLEAN Overwrite,
1938 IN BOOLEAN DontUseBuffer
1939 )
1940 /*++
1941 Routine description:
1942 MTFTP API entry point
1943
1944 Parameters:
1945 Private :=
1946 Operation :=
1947 BufferSizePtr :=
1948 BufferPtr :=
1949 ServerIpPtr :=
1950 FilenamePtr :=
1951 PacketSizePtr :=
1952 MtftpInfoPtr :=
1953 Overwrite :=
1954 DontUseBuffer :=
1955
1956 Returns:
1957 * EFI_INVALID_PARAMETER
1958 * EFI_OUT_OF_RESOURCES
1959 * EFI_BAD_BUFFER_SIZE
1960 * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
1961 * TftpDownload() and TftpUpload().
1962 --*/
1963 {
1964 EFI_PXE_BASE_CODE_IP_FILTER Filter;
1965 EFI_STATUS StatCode;
1966 UINT64 BufferSizeLocal;
1967 UINTN PacketSize;
1968 UINT8 *BufferPtrLocal;
1969
1970 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
1971 Filter.IpCnt = 0;
1972 Filter.reserved = 0;
1973
1974 /* No error has occurred, yet. */
1975 Private->EfiBc.Mode->TftpErrorReceived = FALSE;
1976
1977 /* We must at least have an MTFTP server IP address and
1978 * a pointer to the buffer size.
1979 */
1980 if (!ServerIpPtr || !BufferSizePtr) {
1981 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #1"));
1982
1983 return EFI_INVALID_PARAMETER;
1984 }
1985
1986 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;
1987
1988 //
1989 // make sure filter set to unicast at start
1990 //
1991 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1992 DEBUG (
1993 (EFI_D_NET,
1994 "\nPxeBcMtftp() Exit IpFilter() == %Xh",
1995 StatCode)
1996 );
1997
1998 return StatCode;
1999 }
2000 //
2001 // set unset parms to default values
2002 //
2003 if (!PacketSizePtr) {
2004 *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;
2005 }
2006
2007 if (*PacketSizePtr > *BufferSizePtr) {
2008 *PacketSizePtr = (UINTN) *BufferSizePtr;
2009 }
2010
2011 if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {
2012 *PacketSizePtr = MIN_TFTP_PKT_SIZE;
2013 }
2014
2015 if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {
2016 *PacketSizePtr = BUFFER_ALLOCATE_SIZE;
2017 }
2018
2019 if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {
2020 *PacketSizePtr = MAX_TFTP_PKT_SIZE;
2021 }
2022
2023 if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
2024 StatCode = TftpInfo (
2025 Private,
2026 BufferSizePtr,
2027 ServerIpPtr,
2028 TftpRequestPort,
2029 FilenamePtr,
2030 PacketSizePtr
2031 );
2032
2033 if (StatCode != EFI_SUCCESS) {
2034 DEBUG (
2035 (EFI_D_WARN,
2036 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
2037 StatCode)
2038 );
2039 }
2040
2041 return StatCode;
2042 }
2043
2044 if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {
2045 if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {
2046 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #2"));
2047 return EFI_INVALID_PARAMETER;
2048 } else {
2049 StatCode = TftpInfo (
2050 Private,
2051 BufferSizePtr,
2052 ServerIpPtr,
2053 MtftpInfoPtr->SPort,
2054 FilenamePtr,
2055 PacketSizePtr
2056 );
2057
2058 gBS->Stall (10000);
2059
2060 if (StatCode != EFI_SUCCESS) {
2061 DEBUG (
2062 (EFI_D_WARN,
2063 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
2064 StatCode)
2065 );
2066 }
2067
2068 return StatCode;
2069 }
2070 }
2071
2072 if (!BufferPtr && !DontUseBuffer) {
2073 //
2074 // if dontusebuffer is false and no buffer???
2075 //
2076 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #3"));
2077 //
2078 // DontUseBuffer can be true only for read_file operation
2079 //
2080 return EFI_INVALID_PARAMETER;
2081 }
2082
2083 if (DontUseBuffer) {
2084 BufferPtrLocal = AllocatePool (BUFFER_ALLOCATE_SIZE);
2085 if (BufferPtrLocal == NULL) {
2086 DEBUG ((EFI_D_NET, "\nPxeBcMtftp() Exit #4"));
2087 return EFI_OUT_OF_RESOURCES;
2088 }
2089
2090 BufferSizeLocal = BUFFER_ALLOCATE_SIZE;
2091 } else {
2092 if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {
2093 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #5"));
2094 return EFI_BAD_BUFFER_SIZE;
2095 }
2096
2097 BufferPtrLocal = BufferPtr;
2098 BufferSizeLocal = *BufferSizePtr;
2099 }
2100
2101 switch (Operation) {
2102 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
2103 if (FilenamePtr == NULL ||
2104 MtftpInfoPtr == NULL ||
2105 MtftpInfoPtr->MCastIp.Addr[0] == 0 ||
2106 MtftpInfoPtr->SPort == 0 ||
2107 MtftpInfoPtr->CPort == 0 ||
2108 MtftpInfoPtr->ListenTimeout == 0 ||
2109 MtftpInfoPtr->TransmitTimeout == 0
2110 ) {
2111 StatCode = EFI_INVALID_PARAMETER;
2112 break;
2113 }
2114 //
2115 // try MTFTP - if fails, drop into TFTP read
2116 //
2117 if ((StatCode = MtftpDownload (
2118 Private,
2119 &BufferSizeLocal,
2120 BufferPtrLocal,
2121 ServerIpPtr,
2122 FilenamePtr,
2123 MtftpInfoPtr,
2124 DontUseBuffer
2125 )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
2126 if (BufferSizePtr /* %% !DontUseBuffer */ ) {
2127 *BufferSizePtr = BufferSizeLocal;
2128 }
2129
2130 break;
2131 }
2132 //
2133 // go back to unicast
2134 //
2135 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
2136 break;
2137 }
2138
2139 /* fall thru */
2140 case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
2141 if (FilenamePtr == NULL) {
2142 StatCode = EFI_INVALID_PARAMETER;
2143 break;
2144 }
2145
2146 StatCode = TftpDownload (
2147 Private,
2148 &BufferSizeLocal,
2149 BufferPtrLocal,
2150 ServerIpPtr,
2151 FilenamePtr,
2152 PacketSizePtr,
2153 TftpRequestPort,
2154 TFTP_RRQ,
2155 DontUseBuffer
2156 );
2157
2158 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
2159 if (BufferSizePtr /* !DontUseBuffer */ ) {
2160 *BufferSizePtr = BufferSizeLocal;
2161 }
2162 }
2163
2164 break;
2165
2166 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
2167 if (FilenamePtr == NULL || DontUseBuffer) {
2168 //
2169 // not a valid option
2170 //
2171 StatCode = EFI_INVALID_PARAMETER;
2172 break;
2173 }
2174
2175 StatCode = TftpUpload (
2176 Private,
2177 BufferSizePtr,
2178 BufferPtr,
2179 ServerIpPtr,
2180 FilenamePtr,
2181 PacketSizePtr,
2182 Overwrite
2183 );
2184
2185 if (StatCode != EFI_SUCCESS) {
2186 DEBUG (
2187 (EFI_D_WARN,
2188 "\nPxeBcMtftp() Exit #6 %xh (%r)",
2189 StatCode,
2190 StatCode)
2191 );
2192 }
2193
2194 return StatCode;
2195
2196 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
2197 if (FilenamePtr == NULL || DontUseBuffer) {
2198 //
2199 // not a valid option
2200 //
2201 StatCode = EFI_INVALID_PARAMETER;
2202 break;
2203 }
2204
2205 StatCode = TftpDownload (
2206 Private,
2207 BufferSizePtr,
2208 BufferPtr,
2209 ServerIpPtr,
2210 FilenamePtr,
2211 PacketSizePtr,
2212 TftpRequestPort,
2213 TFTP_DIR,
2214 DontUseBuffer
2215 );
2216
2217 if (StatCode != EFI_SUCCESS) {
2218 DEBUG (
2219 (EFI_D_WARN,
2220 "\nPxeBcMtftp() Exit #7 %xh (%r)",
2221 StatCode,
2222 StatCode)
2223 );
2224 }
2225
2226 return StatCode;
2227
2228 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
2229 if (DontUseBuffer) {
2230 StatCode = EFI_INVALID_PARAMETER;
2231 break;
2232 }
2233
2234 if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {
2235 DEBUG (
2236 (EFI_D_WARN,
2237 "\nPxeBcMtftp() Exit #9 %xh (%r)",
2238 EFI_INVALID_PARAMETER,
2239 EFI_INVALID_PARAMETER)
2240 );
2241
2242 return EFI_INVALID_PARAMETER;
2243 }
2244
2245 StatCode = TftpDownload (
2246 Private,
2247 BufferSizePtr,
2248 BufferPtr,
2249 ServerIpPtr,
2250 (UINT8 *) "/",
2251 PacketSizePtr,
2252 MtftpInfoPtr->SPort,
2253 TFTP_DIR,
2254 DontUseBuffer
2255 );
2256
2257 break;
2258
2259 default:
2260 StatCode = EFI_INVALID_PARAMETER;
2261 }
2262
2263 if (DontUseBuffer) {
2264 FreePool (BufferPtrLocal);
2265 }
2266
2267 if (StatCode != EFI_SUCCESS) {
2268 DEBUG (
2269 (EFI_D_WARN,
2270 "\nPxeBcMtftp() Exit #8 %xh (%r)",
2271 StatCode,
2272 StatCode)
2273 );
2274 }
2275
2276 gBS->Stall (10000);
2277
2278 return StatCode;
2279 }
2280
2281 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2282 EFI_STATUS
2283 EFIAPI
2284 BcMtftp (
2285 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
2286 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
2287 IN OUT VOID *BufferPtr,
2288 IN BOOLEAN Overwrite,
2289 IN OUT UINT64 *BufferSizePtr,
2290 IN UINTN *BlockSizePtr OPTIONAL,
2291 IN EFI_IP_ADDRESS * ServerIpPtr,
2292 IN UINT8 *FilenamePtr,
2293 IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL,
2294 IN BOOLEAN DontUseBuffer
2295 )
2296 /*++
2297 Routine description:
2298 MTFTP API entry point.
2299
2300 Parameters:
2301 This :=
2302 Operation :=
2303 BufferPtr :=
2304 Overwrite :=
2305 BufferSizePtr :=
2306 BlockSizePtr :=
2307 ServerIpPtr :=
2308 FilenamePtr :=
2309 MtftpInfoPtr :=
2310 DontUseBuffer :=
2311
2312 Returns:
2313 * EFI_INVALID_PARAMETER
2314 * Status is also returned from PxeBcMtftp();
2315 --*/
2316 {
2317 EFI_PXE_BASE_CODE_IP_FILTER Filter;
2318 EFI_STATUS StatCode;
2319 PXE_BASECODE_DEVICE *Private;
2320
2321 //
2322 // Lock the instance data and make sure started
2323 //
2324 StatCode = EFI_SUCCESS;
2325
2326 if (This == NULL) {
2327 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
2328 return EFI_INVALID_PARAMETER;
2329 }
2330
2331 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2332
2333 if (Private == NULL) {
2334 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
2335 return EFI_INVALID_PARAMETER;
2336 }
2337
2338 EfiAcquireLock (&Private->Lock);
2339
2340 if (This->Mode == NULL || !This->Mode->Started) {
2341 DEBUG ((EFI_D_ERROR, "BC was not started."));
2342 EfiReleaseLock (&Private->Lock);
2343 return EFI_NOT_STARTED;
2344 }
2345 //
2346 // Issue BC command
2347 //
2348 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
2349 Filter.IpCnt = 0;
2350 Filter.reserved = 0;
2351
2352 DEBUG ((EFI_D_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr));
2353
2354 StatCode = PxeBcMtftp (
2355 Private,
2356 Operation,
2357 BufferSizePtr,
2358 BufferPtr,
2359 ServerIpPtr,
2360 FilenamePtr,
2361 BlockSizePtr,
2362 MtftpInfoPtr,
2363 Overwrite,
2364 DontUseBuffer
2365 );
2366
2367 //
2368 // restore to unicast
2369 //
2370 IpFilter (Private, &Filter);
2371
2372 //
2373 // Unlock the instance data
2374 //
2375 EfiReleaseLock (&Private->Lock);
2376 return StatCode;
2377 }
2378
2379 /* eof - PxeBcMtftp.c */