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