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