]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_mtftp.c
Use Mde library and definition instead of some native definitions in NetLib, to simpl...
[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
67a58d0f 1104 CopyMem (&Filter.IpList[0], &Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS));\r
1105 CopyMem (&Filter.IpList[1], &MtftpInfoPtr->MCastIp, sizeof (EFI_IP_ADDRESS));\r
772db4bb 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
e48e37fc 1130 if (((Status = MtftpListen (\r
772db4bb 1131 Private,\r
1132 &BufferSize,\r
1133 BufferPtrLocal,\r
1134 ServerIpPtr,\r
1135 MtftpInfoPtr,\r
1136 &StartBlock,\r
1137 &NumMissed,\r
1138 TransTimeout,\r
1139 ListenTimeout,\r
1140 LastBlock,\r
1141 DontUseBuffer\r
1142 )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) {\r
1143 return Status;\r
1144 //\r
1145 // failed\r
1146 //\r
e48e37fc 1147 }\r
772db4bb 1148 //\r
1149 // if none were received, start block is not reset\r
1150 //\r
1151 if (StartBlock == LastStartBlock) {\r
1152 UINT8 CompStat;\r
1153\r
1154 //\r
1155 // timed out with none received - try MTFTP open\r
1156 //\r
1157 if ((Status = MtftpOpen (\r
1158 Private,\r
1159 BufferSizePtr,\r
1160 BufferPtr,\r
1161 &Offset,\r
1162 ServerIpPtr,\r
1163 FilenamePtr,\r
1164 MtftpInfoPtr,\r
1165 &CompStat,\r
1166 DontUseBuffer\r
1167 )) != EFI_SUCCESS) {\r
1168 //\r
1169 // open failure - try TFTP\r
1170 //\r
1171 return Status;\r
1172 }\r
1173 //\r
1174 // return code EFI_SUCCESS\r
1175 // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done\r
1176 // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest\r
1177 // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all\r
1178 // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)\r
1179 //\r
1180 if (CompStat == (GOTUNI | GOTMULTI)) {\r
1181 //\r
1182 // finished - got it all\r
1183 //\r
1184 return Status;\r
1185 }\r
1186\r
1187 if (CompStat) {\r
1188 //\r
1189 // offset is two packet lengths\r
1190 //\r
1191 Offset <<= 1;\r
1192 //\r
1193 // last block received\r
1194 //\r
1195 LastStartBlock = 2;\r
1196 } else {\r
1197 Offset = 0;\r
1198 LastStartBlock = 0;\r
1199 }\r
1200\r
1201 ListenTimeout = TransTimeout;\r
1202 continue;\r
1203 }\r
1204 //\r
1205 // did we get the last block\r
1206 //\r
1207 if (Status == EFI_SUCCESS) {\r
1208 //\r
1209 // yes - set the file size if this was first time\r
1210 //\r
1211 if (!LastBlock) {\r
1212 *BufferSizePtr -= BufferSize;\r
1213 }\r
1214 //\r
1215 // if buffer was too small, finished\r
1216 //\r
1217 if (!DontUseBuffer) {\r
1218 return EFI_BUFFER_TOO_SMALL;\r
1219 }\r
1220 //\r
1221 // if we got them all, finished\r
1222 //\r
1223 if (!NumMissed && StartBlock == LastStartBlock + 1) {\r
1224 return Status;\r
1225 }\r
1226 //\r
1227 // did not get them all - set last block\r
1228 //\r
1229 LastBlock = (UINT16) (StartBlock - 1);\r
1230 }\r
1231 //\r
1232 // compute listen timeout\r
1233 //\r
1234 ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed));\r
1235\r
1236 //\r
1237 // reset\r
1238 //\r
1239 Offset = 0;\r
1240 LastStartBlock = 0;\r
1241 }\r
1242}\r
1243\r
1244/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
1245\r
1246/**\r
1247\r
1248\r
1249**/\r
1250STATIC\r
1251EFI_STATUS\r
1252TftpInfo (\r
1253 PXE_BASECODE_DEVICE *Private,\r
1254 UINT64 *BufferSizePtr,\r
1255 EFI_IP_ADDRESS *ServerIpPtr,\r
1256 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,\r
1257 UINT8 *FilenamePtr,\r
1258 UINTN *PacketSizePtr\r
1259 )\r
1260{\r
1261 EFI_PXE_BASE_CODE_UDP_PORT OurPort;\r
1262 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;\r
1263 EFI_STATUS Status;\r
1264 UINT64 BlockNum;\r
1265 UINTN Offset;\r
1266 UINTN ReplyLen;\r
1267 UINT8 *Ptr;\r
1268\r
1269 union {\r
1270 struct Tftpv4Oack OAck2Ptr;\r
1271 struct Tftpv4Ack Ack2Ptr;\r
1272 struct Tftpv4Data Datastr;\r
1273 } u;\r
1274\r
1275 OurPort = 0;\r
1276 ServerReplyPort = 0;\r
1277 ReplyLen = sizeof (u.Datastr.Data);\r
1278\r
1279 //\r
1280 // send a write request with the blocksize option -\r
1281 // sets our IP and port - and receive reply - sets his port\r
1282 // will retry operation up to 3 times if no response,\r
1283 // and will retry without options on an error reply\r
1284 //\r
1285 if ((Status = TftpRwReqwResp (\r
1286 TFTP_RRQ,\r
1287 /* BIGBLKNUMOP | */BKSZOP | TSIZEOP,\r
1288 Private,\r
1289 &u,\r
1290 PacketSizePtr,\r
1291 &ReplyLen,\r
1292 u.Datastr.Data,\r
1293 ServerIpPtr,\r
1294 &SrvPort,\r
1295 &ServerReplyPort,\r
1296 &OurPort,\r
1297 FilenamePtr,\r
1298 REQ_RESP_TIMEOUT\r
1299 )) != EFI_SUCCESS) {\r
1300 DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #1"));\r
1301 return Status;\r
1302 }\r
1303 //\r
1304 // check for good OACK\r
1305 //\r
1306 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {\r
1307 //\r
1308 // now parse it for options\r
1309 // bigblk#\r
1310 //\r
1311 Ptr = FindOption (\r
1312 BigBlkNumOp,\r
1313 sizeof (BigBlkNumOp),\r
1314 u.OAck2Ptr.OpAck[0].Option,\r
1315 ReplyLen + sizeof (u.Ack2Ptr.BlockNum)\r
1316 );\r
1317\r
1318 if (Ptr != NULL) {\r
1319 if (AtoU (Ptr) == 8) {\r
1320 Private->BigBlkNumFlag = TRUE;\r
1321 } else {\r
1322 return EFI_PROTOCOL_ERROR;\r
1323 }\r
1324 }\r
1325 //\r
1326 // blksize\r
1327 //\r
1328 Ptr = FindOption (\r
1329 BlockSizeOp,\r
1330 sizeof (BlockSizeOp),\r
1331 u.OAck2Ptr.OpAck[0].Option,\r
1332 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)\r
1333 );\r
1334\r
1335 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;\r
1336\r
1337 //\r
1338 // tsize\r
1339 //\r
1340 Ptr = FindOption (\r
1341 TsizeOp,\r
1342 sizeof (TsizeOp),\r
1343 u.OAck2Ptr.OpAck[0].Option,\r
1344 ReplyLen\r
1345 );\r
1346\r
1347 if (Ptr != NULL) {\r
1348 *BufferSizePtr = AtoU64 (Ptr);\r
1349\r
1350 //\r
1351 // teminate session with error\r
1352 //\r
1353 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);\r
1354\r
1355 return EFI_SUCCESS;\r
1356 }\r
1357\r
1358 Offset = 0;\r
1359 BlockNum = 0;\r
1360 } else {\r
1361 //\r
1362 // if MTFTP get filesize, return unsupported\r
1363 //\r
1364 if (SrvPort != TftpRequestPort) {\r
1365 SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);\r
1366 DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #3"));\r
1367 return EFI_UNSUPPORTED;\r
1368 }\r
1369\r
1370 Offset = ReplyLen;\r
1371 //\r
1372 // last block received\r
1373 //\r
1374 BlockNum = 1;\r
1375 }\r
1376 //\r
1377 // does not support the option - do a download with no buffer\r
1378 //\r
1379 *BufferSizePtr = 0;\r
1380\r
1381 Status = LockStepReceive (\r
1382 Private,\r
1383 (UINT16) ReplyLen,\r
1384 BufferSizePtr,\r
1385 Offset,\r
687a2e5f 1386 (UINT8 *) &u,\r
772db4bb 1387 ServerIpPtr,\r
1388 &ServerReplyPort,\r
1389 &Private->EfiBc.Mode->StationIp,\r
1390 &OurPort,\r
1391 BlockNum,\r
1392 ACK_TIMEOUT,\r
1393 TRUE\r
1394 );\r
1395\r
1396 if (Status != EFI_SUCCESS) {\r
1397 DEBUG ((DEBUG_WARN, "\nTftpInfo() LockStepReceive() == %Xh", Status));\r
1398 }\r
1399\r
1400 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1401 return Status;\r
1402 }\r
1403\r
1404 return EFI_SUCCESS;\r
1405}\r
1406\r
1407/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
1408\r
1409/**\r
1410\r
1411\r
1412**/\r
1413STATIC\r
1414EFI_STATUS\r
1415TftpDownload (\r
1416 PXE_BASECODE_DEVICE *Private,\r
1417 UINT64 *BufferSizePtr,\r
1418 UINT8 *BufferPtr,\r
1419 EFI_IP_ADDRESS *ServerIpPtr,\r
1420 UINT8 *FilenamePtr,\r
1421 UINTN *PacketSizePtr,\r
1422 EFI_PXE_BASE_CODE_UDP_PORT SrvPort,\r
1423 UINT16 Req,\r
1424 IN BOOLEAN DontUseBuffer\r
1425 )\r
1426{\r
1427 EFI_PXE_BASE_CODE_UDP_PORT OurPort;\r
1428 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;\r
1429 EFI_STATUS Status;\r
1430 UINT64 Offset;\r
1431 UINT64 BlockNum;\r
1432 UINTN ReplyLen;\r
1433 UINT8 *Ptr;\r
1434\r
1435 union {\r
1436 struct Tftpv4Ack Ack2Ptr;\r
1437 struct Tftpv4Oack OAck2Ptr;\r
1438 struct Tftpv4Data Data;\r
1439 struct Tftpv4Ack8 Ack8Ptr;\r
1440 struct Tftpv4Data8 Data8;\r
1441 } U;\r
1442\r
1443 OurPort = 0;\r
1444 ServerReplyPort = 0;\r
1445 ReplyLen = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr);\r
1446\r
1447 //\r
1448 // send a read request with the blocksize option - sets our IP and port\r
1449 // - and receive reply - sets his port will retry operation up to 3\r
1450 // times if no response, and will retry without options on an error\r
1451 // reply\r
1452 //\r
1453 if ((Status = TftpRwReqwResp (\r
1454 Req,\r
1455 /* BIGBLKNUMOP | */BKSZOP,\r
1456 Private,\r
1457 &U,\r
1458 PacketSizePtr,\r
1459 &ReplyLen,\r
1460 BufferPtr,\r
1461 ServerIpPtr,\r
1462 &SrvPort,\r
1463 &ServerReplyPort,\r
1464 &OurPort,\r
1465 FilenamePtr,\r
1466 REQ_RESP_TIMEOUT\r
1467 )) != EFI_SUCCESS) {\r
1468 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #1 %xh (%r)", Status, Status));\r
1469 return Status;\r
1470 }\r
1471 //\r
1472 // check for OACK\r
1473 //\r
1474 if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {\r
1475 //\r
1476 // get the OACK\r
1477 //\r
1478 CopyMem (U.Data.Data, BufferPtr, ReplyLen);\r
1479\r
1480 Ptr = FindOption (\r
1481 BigBlkNumOp,\r
1482 sizeof (BigBlkNumOp),\r
1483 U.OAck2Ptr.OpAck[0].Option,\r
1484 ReplyLen + sizeof (U.Ack2Ptr.BlockNum)\r
1485 );\r
1486\r
1487 if (Ptr != NULL) {\r
1488 if (AtoU (Ptr) == 8) {\r
1489 Private->BigBlkNumFlag = TRUE;\r
1490 } else {\r
1491 return EFI_PROTOCOL_ERROR;\r
1492 }\r
1493 }\r
1494 //\r
1495 // now parse it for blocksize option\r
1496 //\r
1497 Ptr = FindOption (\r
1498 BlockSizeOp,\r
1499 sizeof (BlockSizeOp),\r
1500 U.OAck2Ptr.OpAck[0].Option,\r
1501 ReplyLen += sizeof (U.Ack2Ptr.BlockNum)\r
1502 );\r
1503\r
1504 ReplyLen = (Ptr != NULL) ? AtoU (Ptr) : 512;\r
1505\r
1506 Offset = 0;\r
1507 //\r
1508 // last block received\r
1509 //\r
1510 BlockNum = 0;\r
1511 } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) {\r
1512 //\r
1513 // or data\r
1514 //\r
1515 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #2 %xh (%r)", Status, Status));\r
1516\r
1517 return EFI_PROTOCOL_ERROR;\r
1518 } else {\r
1519 //\r
1520 // got good data packet\r
1521 //\r
1522 Offset = ReplyLen;\r
1523 //\r
1524 // last block received\r
1525 //\r
1526 BlockNum = 1;\r
1527 }\r
1528\r
1529 if (PacketSizePtr != NULL) {\r
1530 *PacketSizePtr = ReplyLen;\r
1531 }\r
1532 //\r
1533 // routine to read rest of file after a successful open (TFTP or MTFTP)\r
1534 // sends ACK and gets next data packet until short packet arrives, then sends\r
1535 // ACK and (hopefully) times out\r
1536 // if first packet has been read, BufferPtr and BufferSize must reflect fact\r
1537 //\r
1538 Status = LockStepReceive (\r
1539 Private,\r
1540 ReplyLen,\r
1541 BufferSizePtr,\r
1542 Offset,\r
1543 BufferPtr,\r
1544 ServerIpPtr,\r
1545 &ServerReplyPort,\r
1546 &Private->EfiBc.Mode->StationIp,\r
1547 &OurPort,\r
1548 BlockNum,\r
1549 ACK_TIMEOUT,\r
1550 DontUseBuffer\r
1551 );\r
1552\r
1553 if (Status != EFI_SUCCESS) {\r
1554 DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #3 %xh (%r)", Status, Status));\r
1555\r
1556 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1557 Status = TftpInfo (\r
1558 Private,\r
1559 BufferSizePtr,\r
1560 ServerIpPtr,\r
1561 SrvPort,\r
1562 FilenamePtr,\r
1563 PacketSizePtr\r
1564 );\r
1565\r
1566 if (!EFI_ERROR (Status)) {\r
1567 Status = EFI_BUFFER_TOO_SMALL;\r
1568 }\r
1569 }\r
1570 }\r
1571\r
1572 return Status;\r
1573}\r
1574\r
1575/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
1576\r
1577/**\r
1578\r
1579\r
1580**/\r
1581STATIC\r
1582EFI_STATUS\r
1583TftpUpload (\r
1584 PXE_BASECODE_DEVICE *Private,\r
1585 UINT64 *BufferSizePtr,\r
1586 VOID *BufferPtr,\r
1587 EFI_IP_ADDRESS *ServerIpPtr,\r
1588 UINT8 *FilenamePtr,\r
1589 UINTN *PacketSizePtr,\r
1590 BOOLEAN Overwrite\r
1591 )\r
1592{\r
1593 struct Tftpv4Ack Header;\r
1594 EFI_PXE_BASE_CODE_UDP_PORT OurPort;\r
1595 EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;\r
1596 EFI_STATUS Status;\r
1597 UINT64 BlockNum;\r
1598 UINT64 TransferSize;\r
1599 UINTN ReplyLen;\r
1600 UINTN TransferLen;\r
1601 UINT16 Options;\r
1602 UINT8 *Ptr;\r
1603\r
1604 union {\r
1605 struct Tftpv4Oack OAck2Ptr;\r
1606 struct Tftpv4Ack Ack2Ptr;\r
1607 struct Tftpv4Data Datastr;\r
1608 } u;\r
1609\r
1610 OurPort = 0;\r
1611 ServerReplyPort = 0;\r
1612 TransferSize = *BufferSizePtr;\r
1613 ReplyLen = sizeof (u.Datastr.Data);\r
1614 Options = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP);\r
1615\r
1616 //\r
1617 // send a write request with the blocksize option - sets our IP and port -\r
1618 // and receive reply - sets his port\r
1619 // will retry operation up to 3 times if no response, and will retry without\r
1620 // options on an error reply\r
1621 //\r
1622 if ((Status = TftpRwReqwResp (\r
1623 TFTP_WRQ,\r
1624 Options,\r
1625 Private,\r
1626 &u,\r
1627 PacketSizePtr,\r
1628 &ReplyLen,\r
1629 u.Datastr.Data,\r
1630 ServerIpPtr,\r
1631 &TftpRequestPort,\r
1632 &ServerReplyPort,\r
1633 &OurPort,\r
1634 FilenamePtr,\r
1635 REQ_RESP_TIMEOUT\r
1636 )) != EFI_SUCCESS) {\r
1637 return Status;\r
1638 }\r
1639 //\r
1640 // check for OACK\r
1641 //\r
1642 if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {\r
1643 //\r
1644 // parse it for blocksize option\r
1645 //\r
1646 Ptr = FindOption (\r
1647 BlockSizeOp,\r
1648 sizeof (BlockSizeOp),\r
1649 u.OAck2Ptr.OpAck[0].Option,\r
1650 ReplyLen += sizeof (u.Ack2Ptr.BlockNum)\r
1651 );\r
1652 *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;\r
1653 }\r
1654 //\r
1655 // or ACK\r
1656 //\r
1657 else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) {\r
1658 //\r
1659 // option was not supported\r
1660 //\r
1661 *PacketSizePtr = 512;\r
1662 } else {\r
1663 return EFI_PROTOCOL_ERROR;\r
1664 }\r
1665 //\r
1666 // loop\r
1667 //\r
1668 Header.OpCode = HTONS (TFTP_DATA);\r
1669 BlockNum = 1;\r
1670 Header.BlockNum = HTONS (1);\r
1671\r
1672 do {\r
1673 UINTN HeaderSize;\r
1674 INTN Retries;\r
1675\r
1676 Retries = NUM_ACK_RETRIES;\r
1677 HeaderSize = sizeof (Header);\r
1678 TransferLen = (UINTN) (MIN (*PacketSizePtr, TransferSize));\r
1679\r
1680 //\r
1681 // write a data packet and get an ack\r
1682 //\r
1683 do {\r
1684 //\r
1685 // write\r
1686 //\r
1687 if ((Status = UdpWrite (\r
1688 Private,\r
1689 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
1690 ServerIpPtr,\r
1691 &ServerReplyPort,\r
1692 0,\r
1693 0,\r
1694 &OurPort,\r
1695 &HeaderSize,\r
1696 &Header,\r
1697 &TransferLen,\r
1698 BufferPtr\r
1699 )) != EFI_SUCCESS) {\r
1700 return Status;\r
1701 }\r
1702 //\r
1703 // read reply\r
1704 //\r
1705 ReplyLen = sizeof (u.Datastr.Data);\r
1706\r
1707 if ((Status = TftpUdpRead (\r
1708 Private,\r
1709 0,\r
1710 &u,\r
1711 &ReplyLen,\r
1712 u.Datastr.Data,\r
1713 ServerIpPtr,\r
1714 &ServerReplyPort,\r
1715 0,\r
1716 &OurPort,\r
1717 ACK_TIMEOUT\r
1718 )) == EFI_SUCCESS) {\r
1719 //\r
1720 // check for ACK for this data packet\r
1721 //\r
1722 if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) {\r
1723 return EFI_PROTOCOL_ERROR;\r
1724 }\r
1725\r
1726 if (u.Ack2Ptr.BlockNum != Header.BlockNum) {\r
1727 //\r
1728 // not for this packet - continue\r
1729 //\r
1730 Status = EFI_TIMEOUT;\r
1731 }\r
1732 }\r
1733 } while (Status == EFI_TIMEOUT && --Retries);\r
1734\r
1735 if (Status != EFI_SUCCESS) {\r
1736 return Status;\r
1737 }\r
1738\r
1739 BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen);\r
1740 TransferSize -= TransferLen;\r
1741 ++BlockNum;\r
1742 Header.BlockNum = HTONS ((UINT16) BlockNum);\r
1743 } while (TransferLen == *PacketSizePtr);\r
1744\r
1745 return EFI_SUCCESS;\r
1746}\r
1747\r
1748/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
1749\r
1750/**\r
1751\r
1752 @return * EFI_INVALID_PARAMETER\r
1753 @return * EFI_OUT_OF_RESOURCES\r
1754 @return * EFI_BAD_BUFFER_SIZE\r
1755 @return * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),\r
1756 @return * TftpDownload() and TftpUpload().\r
1757\r
1758**/\r
1759EFI_STATUS\r
1760PxeBcMtftp (\r
1761 PXE_BASECODE_DEVICE *Private,\r
1762 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,\r
1763 UINT64 *BufferSizePtr,\r
1764 VOID *BufferPtr,\r
1765 EFI_IP_ADDRESS *ServerIpPtr,\r
1766 UINT8 *FilenamePtr,\r
1767 UINTN *PacketSizePtr,\r
1768 IN EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, OPTIONAL\r
1769 IN BOOLEAN Overwrite,\r
1770 IN BOOLEAN DontUseBuffer\r
1771 )\r
1772{\r
1773 EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
1774 EFI_STATUS StatCode;\r
1775 EFI_STATUS Status;\r
1776 UINT64 BufferSizeLocal;\r
1777 UINTN PacketSize;\r
1778 UINT8 *BufferPtrLocal;\r
1779\r
1780 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
1781 Filter.IpCnt = 0;\r
1782 Filter.reserved = 0;\r
1783\r
1784 /* No error has occurred, yet. */\r
1785 Private->EfiBc.Mode->TftpErrorReceived = FALSE;\r
1786\r
1787 /* We must at least have an MTFTP server IP address and\r
1788 * a pointer to the buffer size.\r
1789 */\r
1790 if (!ServerIpPtr || !BufferSizePtr) {\r
1791 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #1"));\r
1792\r
1793 return EFI_INVALID_PARAMETER;\r
1794 }\r
1795\r
1796 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;\r
1797\r
1798 //\r
1799 // make sure filter set to unicast at start\r
1800 //\r
1801 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
1802 DEBUG (\r
1803 (DEBUG_NET,\r
1804 "\nPxeBcMtftp() Exit IpFilter() == %Xh",\r
1805 StatCode)\r
1806 );\r
1807\r
1808 return StatCode;\r
1809 }\r
1810 //\r
1811 // set unset parms to default values\r
1812 //\r
1813 if (!PacketSizePtr) {\r
1814 *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;\r
1815 }\r
1816\r
07e3550e 1817 if ((*PacketSizePtr > *BufferSizePtr) &&\r
1818 (Operation != EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) &&\r
1819 (Operation != EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE)) {\r
1820 *PacketSizePtr = MAX ((UINTN) *BufferSizePtr, MIN_TFTP_PKT_SIZE);\r
772db4bb 1821 }\r
1822\r
1823 if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {\r
1824 *PacketSizePtr = MIN_TFTP_PKT_SIZE;\r
1825 return EFI_INVALID_PARAMETER;\r
1826 }\r
1827\r
1828 if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {\r
1829 *PacketSizePtr = BUFFER_ALLOCATE_SIZE;\r
1830 }\r
1831\r
1832 if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {\r
1833 *PacketSizePtr = MAX_TFTP_PKT_SIZE;\r
1834 }\r
1835\r
1836 if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {\r
1837 StatCode = TftpInfo (\r
1838 Private,\r
1839 BufferSizePtr,\r
1840 ServerIpPtr,\r
1841 TftpRequestPort,\r
1842 FilenamePtr,\r
1843 PacketSizePtr\r
1844 );\r
1845\r
1846 if (StatCode != EFI_SUCCESS) {\r
1847 DEBUG (\r
1848 (DEBUG_WARN,\r
1849 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",\r
1850 StatCode)\r
1851 );\r
1852 }\r
1853\r
1854 return StatCode;\r
1855 }\r
1856\r
1857 if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {\r
1858 if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {\r
1859 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #2"));\r
1860 return EFI_INVALID_PARAMETER;\r
1861 } else {\r
1862 StatCode = TftpInfo (\r
1863 Private,\r
1864 BufferSizePtr,\r
1865 ServerIpPtr,\r
1866 MtftpInfoPtr->SPort,\r
1867 FilenamePtr,\r
1868 PacketSizePtr\r
1869 );\r
1870\r
1871 gBS->Stall (10000);\r
1872\r
1873 if (StatCode != EFI_SUCCESS) {\r
1874 DEBUG (\r
1875 (DEBUG_WARN,\r
1876 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",\r
1877 StatCode)\r
1878 );\r
1879 }\r
1880\r
1881 return StatCode;\r
1882 }\r
1883 }\r
1884\r
1885 if (!BufferPtr && !DontUseBuffer) {\r
1886 //\r
1887 // if dontusebuffer is false and no buffer???\r
1888 //\r
1889 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #3"));\r
1890 //\r
1891 // DontUseBuffer can be true only for read_file operation\r
1892 //\r
1893 return EFI_INVALID_PARAMETER;\r
1894 }\r
1895\r
1896 if (DontUseBuffer) {\r
1897 Status = gBS->AllocatePool (\r
1898 EfiBootServicesData,\r
1899 BUFFER_ALLOCATE_SIZE,\r
687a2e5f 1900 (VOID **) &BufferPtrLocal\r
772db4bb 1901 );\r
1902\r
1903 if (EFI_ERROR (Status) || BufferPtrLocal == NULL) {\r
1904 DEBUG ((DEBUG_NET, "\nPxeBcMtftp() Exit #4"));\r
1905 return EFI_OUT_OF_RESOURCES;\r
1906 }\r
1907\r
1908 BufferSizeLocal = BUFFER_ALLOCATE_SIZE;\r
1909 } else {\r
1910 if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {\r
1911 DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #5"));\r
1912 return EFI_BAD_BUFFER_SIZE;\r
1913 }\r
1914\r
1915 BufferPtrLocal = BufferPtr;\r
1916 BufferSizeLocal = *BufferSizePtr;\r
1917 }\r
1918\r
1919 switch (Operation) {\r
1920 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:\r
1921 if (FilenamePtr == NULL ||\r
1922 MtftpInfoPtr == NULL ||\r
1923 MtftpInfoPtr->MCastIp.Addr[0] == 0 ||\r
1924 MtftpInfoPtr->SPort == 0 ||\r
1925 MtftpInfoPtr->CPort == 0 ||\r
1926 MtftpInfoPtr->ListenTimeout == 0 ||\r
1927 MtftpInfoPtr->TransmitTimeout == 0\r
1928 ) {\r
1929 StatCode = EFI_INVALID_PARAMETER;\r
1930 break;\r
1931 }\r
1932 //\r
1933 // try MTFTP - if fails, drop into TFTP read\r
1934 //\r
1935 if ((StatCode = MtftpDownload (\r
1936 Private,\r
1937 &BufferSizeLocal,\r
1938 BufferPtrLocal,\r
1939 ServerIpPtr,\r
1940 FilenamePtr,\r
1941 MtftpInfoPtr,\r
1942 DontUseBuffer\r
1943 )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
1944 if (BufferSizePtr /* %% !DontUseBuffer */ ) {\r
1945 *BufferSizePtr = BufferSizeLocal;\r
1946 }\r
1947\r
1948 break;\r
1949 }\r
1950 //\r
1951 // go back to unicast\r
1952 //\r
1953 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
1954 break;\r
1955 }\r
1956\r
1957 /* fall thru */\r
1958 case EFI_PXE_BASE_CODE_TFTP_READ_FILE:\r
1959 if (FilenamePtr == NULL) {\r
1960 StatCode = EFI_INVALID_PARAMETER;\r
1961 break;\r
1962 }\r
1963\r
1964 StatCode = TftpDownload (\r
1965 Private,\r
1966 &BufferSizeLocal,\r
1967 BufferPtrLocal,\r
1968 ServerIpPtr,\r
1969 FilenamePtr,\r
1970 PacketSizePtr,\r
1971 TftpRequestPort,\r
1972 TFTP_RRQ,\r
1973 DontUseBuffer\r
1974 );\r
1975\r
1976 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
1977 if (BufferSizePtr /* !DontUseBuffer */ ) {\r
1978 *BufferSizePtr = BufferSizeLocal;\r
1979 }\r
1980 }\r
1981\r
1982 break;\r
1983\r
1984 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:\r
1985 if (FilenamePtr == NULL || DontUseBuffer) {\r
1986 //\r
1987 // not a valid option\r
1988 //\r
1989 StatCode = EFI_INVALID_PARAMETER;\r
1990 break;\r
1991 }\r
1992\r
1993 StatCode = TftpUpload (\r
1994 Private,\r
1995 BufferSizePtr,\r
1996 BufferPtr,\r
1997 ServerIpPtr,\r
1998 FilenamePtr,\r
1999 PacketSizePtr,\r
2000 Overwrite\r
2001 );\r
2002\r
2003 if (StatCode != EFI_SUCCESS) {\r
2004 DEBUG (\r
2005 (DEBUG_WARN,\r
2006 "\nPxeBcMtftp() Exit #6 %xh (%r)",\r
2007 StatCode,\r
2008 StatCode)\r
2009 );\r
2010 }\r
2011\r
2012 return StatCode;\r
2013\r
2014 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:\r
2015 if (FilenamePtr == NULL || DontUseBuffer) {\r
2016 //\r
2017 // not a valid option\r
2018 //\r
2019 StatCode = EFI_INVALID_PARAMETER;\r
2020 break;\r
2021 }\r
2022\r
2023 StatCode = TftpDownload (\r
2024 Private,\r
2025 BufferSizePtr,\r
2026 BufferPtr,\r
2027 ServerIpPtr,\r
2028 FilenamePtr,\r
2029 PacketSizePtr,\r
2030 TftpRequestPort,\r
2031 TFTP_DIR,\r
2032 DontUseBuffer\r
2033 );\r
2034\r
2035 if (StatCode != EFI_SUCCESS) {\r
2036 DEBUG (\r
2037 (DEBUG_WARN,\r
2038 "\nPxeBcMtftp() Exit #7 %xh (%r)",\r
2039 StatCode,\r
2040 StatCode)\r
2041 );\r
2042 }\r
2043\r
2044 return StatCode;\r
2045\r
2046 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:\r
2047 if (DontUseBuffer) {\r
2048 StatCode = EFI_INVALID_PARAMETER;\r
2049 break;\r
2050 }\r
2051\r
2052 if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {\r
2053 DEBUG (\r
2054 (DEBUG_WARN,\r
2055 "\nPxeBcMtftp() Exit #9 %xh (%r)",\r
2056 EFI_INVALID_PARAMETER,\r
2057 EFI_INVALID_PARAMETER)\r
2058 );\r
2059\r
2060 return EFI_INVALID_PARAMETER;\r
2061 }\r
2062\r
2063 StatCode = TftpDownload (\r
2064 Private,\r
2065 BufferSizePtr,\r
2066 BufferPtr,\r
2067 ServerIpPtr,\r
2068 (UINT8 *) "/",\r
2069 PacketSizePtr,\r
2070 MtftpInfoPtr->SPort,\r
2071 TFTP_DIR,\r
2072 DontUseBuffer\r
2073 );\r
2074\r
2075 break;\r
2076\r
2077 default:\r
2078 StatCode = EFI_INVALID_PARAMETER;\r
2079 }\r
2080\r
2081 if (DontUseBuffer) {\r
2082 gBS->FreePool (BufferPtrLocal);\r
2083 }\r
2084\r
2085 if (StatCode != EFI_SUCCESS) {\r
2086 DEBUG (\r
2087 (DEBUG_WARN,\r
2088 "\nPxeBcMtftp() Exit #8 %xh (%r)",\r
2089 StatCode,\r
2090 StatCode)\r
2091 );\r
2092 }\r
2093\r
2094 gBS->Stall (10000);\r
2095\r
2096 return StatCode;\r
2097}\r
2098\r
2099/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
2100\r
2101/**\r
2102\r
2103 @return * EFI_INVALID_PARAMETER\r
2104 @return * Status is also returned from PxeBcMtftp();\r
2105\r
2106**/\r
2107EFI_STATUS\r
2108EFIAPI\r
2109BcMtftp (\r
2110 IN EFI_PXE_BASE_CODE_PROTOCOL * This,\r
2111 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,\r
2112 IN OUT VOID *BufferPtr,\r
2113 IN BOOLEAN Overwrite,\r
2114 IN OUT UINT64 *BufferSizePtr,\r
2115 IN UINTN *BlockSizePtr OPTIONAL,\r
2116 IN EFI_IP_ADDRESS * ServerIpPtr,\r
2117 IN UINT8 *FilenamePtr,\r
2118 IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL,\r
2119 IN BOOLEAN DontUseBuffer\r
2120 )\r
2121{\r
2122 EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
2123 EFI_STATUS StatCode;\r
2124 PXE_BASECODE_DEVICE *Private;\r
2125\r
2126 //\r
2127 // Lock the instance data and make sure started\r
2128 //\r
2129 StatCode = EFI_SUCCESS;\r
2130\r
2131 if (This == NULL) {\r
2132 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
2133 return EFI_INVALID_PARAMETER;\r
2134 }\r
2135\r
2136 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
2137\r
2138 if (Private == NULL) {\r
2139 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
2140 return EFI_INVALID_PARAMETER;\r
2141 }\r
2142\r
2143 if (!IS_INADDR_UNICAST (ServerIpPtr)) {\r
2144 //\r
2145 // The station IP is not a unicast address.\r
2146 //\r
2147 return EFI_INVALID_PARAMETER;\r
2148 }\r
2149\r
2150 EfiAcquireLock (&Private->Lock);\r
2151\r
2152 if (This->Mode == NULL || !This->Mode->Started) {\r
2153 DEBUG ((DEBUG_ERROR, "BC was not started."));\r
2154 EfiReleaseLock (&Private->Lock);\r
2155 return EFI_NOT_STARTED;\r
2156 }\r
2157 //\r
2158 // Issue BC command\r
2159 //\r
2160 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
2161 Filter.IpCnt = 0;\r
2162 Filter.reserved = 0;\r
2163\r
2164 DEBUG ((DEBUG_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr));\r
2165\r
2166 StatCode = PxeBcMtftp (\r
2167 Private,\r
2168 Operation,\r
2169 BufferSizePtr,\r
2170 BufferPtr,\r
2171 ServerIpPtr,\r
2172 FilenamePtr,\r
2173 BlockSizePtr,\r
2174 MtftpInfoPtr,\r
2175 Overwrite,\r
2176 DontUseBuffer\r
2177 );\r
2178\r
2179 //\r
2180 // restore to unicast\r
2181 //\r
2182 IpFilter (Private, &Filter);\r
2183\r
2184 //\r
2185 // Unlock the instance data\r
2186 //\r
2187 EfiReleaseLock (&Private->Lock);\r
2188 return StatCode;\r
2189}\r
2190\r
2191/* eof - PxeBcMtftp.c */\r