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