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