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