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