]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c
1. Remove #ifdef _MSC_EXTENSION_ from all source files
[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
1966 EFI_STATUS Status;\r
1967 UINT64 BufferSizeLocal;\r
1968 UINTN PacketSize;\r
1969 UINT8 *BufferPtrLocal;\r
1970\r
1971 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
1972 Filter.IpCnt = 0;\r
1973 Filter.reserved = 0;\r
1974\r
1975 /* No error has occurred, yet. */\r
1976 Private->EfiBc.Mode->TftpErrorReceived = FALSE;\r
1977\r
1978 /* We must at least have an MTFTP server IP address and\r
1979 * a pointer to the buffer size.\r
1980 */\r
1981 if (!ServerIpPtr || !BufferSizePtr) {\r
1982 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #1"));\r
1983\r
1984 return EFI_INVALID_PARAMETER;\r
1985 }\r
1986\r
1987 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;\r
1988\r
1989 //\r
1990 // make sure filter set to unicast at start\r
1991 //\r
1992 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
1993 DEBUG (\r
1994 (EFI_D_NET,\r
1995 "\nPxeBcMtftp() Exit IpFilter() == %Xh",\r
1996 StatCode)\r
1997 );\r
1998\r
1999 return StatCode;\r
2000 }\r
2001 //\r
2002 // set unset parms to default values\r
2003 //\r
2004 if (!PacketSizePtr) {\r
2005 *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;\r
2006 }\r
2007\r
2008 if (*PacketSizePtr > *BufferSizePtr) {\r
2009 *PacketSizePtr = (UINTN) *BufferSizePtr;\r
2010 }\r
2011\r
2012 if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {\r
2013 *PacketSizePtr = MIN_TFTP_PKT_SIZE;\r
2014 }\r
2015\r
2016 if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {\r
2017 *PacketSizePtr = BUFFER_ALLOCATE_SIZE;\r
2018 }\r
2019\r
2020 if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {\r
2021 *PacketSizePtr = MAX_TFTP_PKT_SIZE;\r
2022 }\r
2023\r
2024 if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {\r
2025 StatCode = TftpInfo (\r
2026 Private,\r
2027 BufferSizePtr,\r
2028 ServerIpPtr,\r
2029 TftpRequestPort,\r
2030 FilenamePtr,\r
2031 PacketSizePtr\r
2032 );\r
2033\r
2034 if (StatCode != EFI_SUCCESS) {\r
2035 DEBUG (\r
2036 (EFI_D_WARN,\r
2037 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",\r
2038 StatCode)\r
2039 );\r
2040 }\r
2041\r
2042 return StatCode;\r
2043 }\r
2044\r
2045 if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {\r
2046 if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {\r
2047 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #2"));\r
2048 return EFI_INVALID_PARAMETER;\r
2049 } else {\r
2050 StatCode = TftpInfo (\r
2051 Private,\r
2052 BufferSizePtr,\r
2053 ServerIpPtr,\r
2054 MtftpInfoPtr->SPort,\r
2055 FilenamePtr,\r
2056 PacketSizePtr\r
2057 );\r
2058\r
2059 gBS->Stall (10000);\r
2060\r
2061 if (StatCode != EFI_SUCCESS) {\r
2062 DEBUG (\r
2063 (EFI_D_WARN,\r
2064 "\nPxeBcMtftp() Exit TftpInfo() == %Xh",\r
2065 StatCode)\r
2066 );\r
2067 }\r
2068\r
2069 return StatCode;\r
2070 }\r
2071 }\r
2072\r
2073 if (!BufferPtr && !DontUseBuffer) {\r
2074 //\r
2075 // if dontusebuffer is false and no buffer???\r
2076 //\r
2077 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #3"));\r
2078 //\r
2079 // DontUseBuffer can be true only for read_file operation\r
2080 //\r
2081 return EFI_INVALID_PARAMETER;\r
2082 }\r
2083\r
2084 if (DontUseBuffer) {\r
2085 Status = gBS->AllocatePool (\r
2086 EfiBootServicesData,\r
2087 BUFFER_ALLOCATE_SIZE,\r
2088 (VOID **) &BufferPtrLocal\r
2089 );\r
2090\r
2091 if (EFI_ERROR (Status) || BufferPtrLocal == NULL) {\r
2092 DEBUG ((EFI_D_NET, "\nPxeBcMtftp() Exit #4"));\r
2093 return EFI_OUT_OF_RESOURCES;\r
2094 }\r
2095\r
2096 BufferSizeLocal = BUFFER_ALLOCATE_SIZE;\r
2097 } else {\r
2098 if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {\r
2099 DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #5"));\r
2100 return EFI_BAD_BUFFER_SIZE;\r
2101 }\r
2102\r
2103 BufferPtrLocal = BufferPtr;\r
2104 BufferSizeLocal = *BufferSizePtr;\r
2105 }\r
2106\r
2107 switch (Operation) {\r
2108 case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:\r
2109 if (FilenamePtr == NULL ||\r
2110 MtftpInfoPtr == NULL ||\r
2111 MtftpInfoPtr->MCastIp.Addr[0] == 0 ||\r
2112 MtftpInfoPtr->SPort == 0 ||\r
2113 MtftpInfoPtr->CPort == 0 ||\r
2114 MtftpInfoPtr->ListenTimeout == 0 ||\r
2115 MtftpInfoPtr->TransmitTimeout == 0\r
2116 ) {\r
2117 StatCode = EFI_INVALID_PARAMETER;\r
2118 break;\r
2119 }\r
2120 //\r
2121 // try MTFTP - if fails, drop into TFTP read\r
2122 //\r
2123 if ((StatCode = MtftpDownload (\r
2124 Private,\r
2125 &BufferSizeLocal,\r
2126 BufferPtrLocal,\r
2127 ServerIpPtr,\r
2128 FilenamePtr,\r
2129 MtftpInfoPtr,\r
2130 DontUseBuffer\r
2131 )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
2132 if (BufferSizePtr /* %% !DontUseBuffer */ ) {\r
2133 *BufferSizePtr = BufferSizeLocal;\r
2134 }\r
2135\r
2136 break;\r
2137 }\r
2138 //\r
2139 // go back to unicast\r
2140 //\r
2141 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
2142 break;\r
2143 }\r
2144\r
2145 /* fall thru */\r
2146 case EFI_PXE_BASE_CODE_TFTP_READ_FILE:\r
2147 if (FilenamePtr == NULL) {\r
2148 StatCode = EFI_INVALID_PARAMETER;\r
2149 break;\r
2150 }\r
2151\r
2152 StatCode = TftpDownload (\r
2153 Private,\r
2154 &BufferSizeLocal,\r
2155 BufferPtrLocal,\r
2156 ServerIpPtr,\r
2157 FilenamePtr,\r
2158 PacketSizePtr,\r
2159 TftpRequestPort,\r
2160 TFTP_RRQ,\r
2161 DontUseBuffer\r
2162 );\r
2163\r
2164 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
2165 if (BufferSizePtr /* !DontUseBuffer */ ) {\r
2166 *BufferSizePtr = BufferSizeLocal;\r
2167 }\r
2168 }\r
2169\r
2170 break;\r
2171\r
2172 case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:\r
2173 if (FilenamePtr == NULL || DontUseBuffer) {\r
2174 //\r
2175 // not a valid option\r
2176 //\r
2177 StatCode = EFI_INVALID_PARAMETER;\r
2178 break;\r
2179 }\r
2180\r
2181 StatCode = TftpUpload (\r
2182 Private,\r
2183 BufferSizePtr,\r
2184 BufferPtr,\r
2185 ServerIpPtr,\r
2186 FilenamePtr,\r
2187 PacketSizePtr,\r
2188 Overwrite\r
2189 );\r
2190\r
2191 if (StatCode != EFI_SUCCESS) {\r
2192 DEBUG (\r
2193 (EFI_D_WARN,\r
2194 "\nPxeBcMtftp() Exit #6 %xh (%r)",\r
2195 StatCode,\r
2196 StatCode)\r
2197 );\r
2198 }\r
2199\r
2200 return StatCode;\r
2201\r
2202 case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:\r
2203 if (FilenamePtr == NULL || DontUseBuffer) {\r
2204 //\r
2205 // not a valid option\r
2206 //\r
2207 StatCode = EFI_INVALID_PARAMETER;\r
2208 break;\r
2209 }\r
2210\r
2211 StatCode = TftpDownload (\r
2212 Private,\r
2213 BufferSizePtr,\r
2214 BufferPtr,\r
2215 ServerIpPtr,\r
2216 FilenamePtr,\r
2217 PacketSizePtr,\r
2218 TftpRequestPort,\r
2219 TFTP_DIR,\r
2220 DontUseBuffer\r
2221 );\r
2222\r
2223 if (StatCode != EFI_SUCCESS) {\r
2224 DEBUG (\r
2225 (EFI_D_WARN,\r
2226 "\nPxeBcMtftp() Exit #7 %xh (%r)",\r
2227 StatCode,\r
2228 StatCode)\r
2229 );\r
2230 }\r
2231\r
2232 return StatCode;\r
2233\r
2234 case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:\r
2235 if (DontUseBuffer) {\r
2236 StatCode = EFI_INVALID_PARAMETER;\r
2237 break;\r
2238 }\r
2239\r
2240 if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {\r
2241 DEBUG (\r
2242 (EFI_D_WARN,\r
2243 "\nPxeBcMtftp() Exit #9 %xh (%r)",\r
2244 EFI_INVALID_PARAMETER,\r
2245 EFI_INVALID_PARAMETER)\r
2246 );\r
2247\r
2248 return EFI_INVALID_PARAMETER;\r
2249 }\r
2250\r
2251 StatCode = TftpDownload (\r
2252 Private,\r
2253 BufferSizePtr,\r
2254 BufferPtr,\r
2255 ServerIpPtr,\r
2256 (UINT8 *) "/",\r
2257 PacketSizePtr,\r
2258 MtftpInfoPtr->SPort,\r
2259 TFTP_DIR,\r
2260 DontUseBuffer\r
2261 );\r
2262\r
2263 break;\r
2264\r
2265 default:\r
2266 StatCode = EFI_INVALID_PARAMETER;\r
2267 }\r
2268\r
2269 if (DontUseBuffer) {\r
2270 gBS->FreePool (BufferPtrLocal);\r
2271 }\r
2272\r
2273 if (StatCode != EFI_SUCCESS) {\r
2274 DEBUG (\r
2275 (EFI_D_WARN,\r
2276 "\nPxeBcMtftp() Exit #8 %xh (%r)",\r
2277 StatCode,\r
2278 StatCode)\r
2279 );\r
2280 }\r
2281\r
2282 gBS->Stall (10000);\r
2283\r
2284 return StatCode;\r
2285}\r
2286\r
2287/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
2288EFI_STATUS\r
2289EFIAPI\r
2290BcMtftp (\r
2291 IN EFI_PXE_BASE_CODE_PROTOCOL * This,\r
2292 IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,\r
2293 IN OUT VOID *BufferPtr,\r
2294 IN BOOLEAN Overwrite,\r
2295 IN OUT UINT64 *BufferSizePtr,\r
2296 IN UINTN *BlockSizePtr OPTIONAL,\r
2297 IN EFI_IP_ADDRESS * ServerIpPtr,\r
2298 IN UINT8 *FilenamePtr,\r
2299 IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL,\r
2300 IN BOOLEAN DontUseBuffer\r
2301 )\r
2302/*++\r
2303Routine description:\r
2304 MTFTP API entry point.\r
2305\r
2306Parameters:\r
e5f461a8 2307 This :=\r
2308 Operation :=\r
2309 BufferPtr :=\r
2310 Overwrite :=\r
2311 BufferSizePtr :=\r
2312 BlockSizePtr :=\r
2313 ServerIpPtr :=\r
2314 FilenamePtr :=\r
2315 MtftpInfoPtr :=\r
2316 DontUseBuffer :=\r
878ddf1f 2317\r
2318Returns:\r
2319 * EFI_INVALID_PARAMETER\r
2320 * Status is also returned from PxeBcMtftp();\r
2321--*/\r
2322{\r
2323 EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
2324 EFI_STATUS StatCode;\r
2325 PXE_BASECODE_DEVICE *Private;\r
2326\r
2327 //\r
2328 // Lock the instance data and make sure started\r
2329 //\r
2330 StatCode = EFI_SUCCESS;\r
2331\r
2332 if (This == NULL) {\r
2333 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));\r
2334 return EFI_INVALID_PARAMETER;\r
2335 }\r
2336\r
2337 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
2338\r
2339 if (Private == NULL) {\r
2340 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
2341 return EFI_INVALID_PARAMETER;\r
2342 }\r
2343\r
2344 EfiAcquireLock (&Private->Lock);\r
2345\r
2346 if (This->Mode == NULL || !This->Mode->Started) {\r
2347 DEBUG ((EFI_D_ERROR, "BC was not started."));\r
2348 EfiReleaseLock (&Private->Lock);\r
2349 return EFI_NOT_STARTED;\r
2350 }\r
2351 //\r
2352 // Issue BC command\r
2353 //\r
2354 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
2355 Filter.IpCnt = 0;\r
2356 Filter.reserved = 0;\r
2357\r
2358 DEBUG ((EFI_D_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr));\r
2359\r
2360 StatCode = PxeBcMtftp (\r
2361 Private,\r
2362 Operation,\r
2363 BufferSizePtr,\r
2364 BufferPtr,\r
2365 ServerIpPtr,\r
2366 FilenamePtr,\r
2367 BlockSizePtr,\r
2368 MtftpInfoPtr,\r
2369 Overwrite,\r
2370 DontUseBuffer\r
2371 );\r
2372\r
2373 //\r
2374 // restore to unicast\r
2375 //\r
2376 IpFilter (Private, &Filter);\r
2377\r
2378 //\r
2379 // Unlock the instance data\r
2380 //\r
2381 EfiReleaseLock (&Private->Lock);\r
2382 return StatCode;\r
2383}\r
2384\r
2385/* eof - PxeBcMtftp.c */\r