• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Functions implementation related with Mtftp for UefiPxeBc Driver.
3 
4   Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "PxeBcImpl.h"
17 
18 CHAR8 *mMtftpOptions[PXE_MTFTP_OPTION_MAXIMUM_INDEX] = {
19   "blksize",
20   "timeout",
21   "tsize",
22   "multicast"
23 };
24 
25 
26 /**
27   This is a callback function when packets are received or transmitted in Mtftp driver.
28 
29   A callback function that is provided by the caller to intercept
30   the EFI_MTFTP6_OPCODE_DATA or EFI_MTFTP6_OPCODE_DATA8 packets processed in the
31   EFI_MTFTP6_PROTOCOL.ReadFile() function, and alternatively to intercept
32   EFI_MTFTP6_OPCODE_OACK or EFI_MTFTP6_OPCODE_ERROR packets during a call to
33   EFI_MTFTP6_PROTOCOL.ReadFile(), WriteFile() or ReadDirectory().
34 
35   @param[in]  This           Pointer to EFI_MTFTP6_PROTOCOL.
36   @param[in]  Token          Pointer to EFI_MTFTP6_TOKEN.
37   @param[in]  PacketLen      Length of EFI_MTFTP6_PACKET.
38   @param[in]  Packet         Pointer to EFI_MTFTP6_PACKET to be checked.
39 
40   @retval EFI_SUCCESS    The current operation succeeded.
41   @retval EFI_ABORTED    Abort the current transfer process.
42 
43 **/
44 EFI_STATUS
45 EFIAPI
PxeBcMtftp6CheckPacket(IN EFI_MTFTP6_PROTOCOL * This,IN EFI_MTFTP6_TOKEN * Token,IN UINT16 PacketLen,IN EFI_MTFTP6_PACKET * Packet)46 PxeBcMtftp6CheckPacket (
47   IN EFI_MTFTP6_PROTOCOL              *This,
48   IN EFI_MTFTP6_TOKEN                 *Token,
49   IN UINT16                           PacketLen,
50   IN EFI_MTFTP6_PACKET                *Packet
51   )
52 {
53   PXEBC_PRIVATE_DATA                  *Private;
54   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
55   EFI_STATUS                          Status;
56 
57   Private   = (PXEBC_PRIVATE_DATA *) Token->Context;
58   Callback  = Private->PxeBcCallback;
59   Status    = EFI_SUCCESS;
60 
61   if (Packet->OpCode == EFI_MTFTP6_OPCODE_ERROR) {
62     //
63     // Store the tftp error message into mode data and set the received flag.
64     //
65     Private->Mode.TftpErrorReceived   = TRUE;
66     Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
67     AsciiStrnCpyS (
68       Private->Mode.TftpError.ErrorString,
69       PXE_MTFTP_ERROR_STRING_LENGTH,
70       (CHAR8 *) Packet->Error.ErrorMessage,
71       PXE_MTFTP_ERROR_STRING_LENGTH - 1
72       );
73     Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1] = '\0';
74   }
75 
76   if (Callback != NULL) {
77     //
78     // Callback to user if has when received any tftp packet.
79     //
80     Status = Callback->Callback (
81                         Callback,
82                         Private->Function,
83                         TRUE,
84                         PacketLen,
85                         (EFI_PXE_BASE_CODE_PACKET *) Packet
86                         );
87     if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
88       //
89       // User wants to abort current process if not EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE.
90       //
91       Status = EFI_ABORTED;
92     } else {
93       //
94       // User wants to continue current process if EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE.
95       //
96       Status = EFI_SUCCESS;
97     }
98   }
99 
100   return Status;
101 }
102 
103 
104 /**
105   This function is to get the size of a file using Tftp.
106 
107   @param[in]      Private        Pointer to PxeBc private data.
108   @param[in]      Config         Pointer to EFI_MTFTP6_CONFIG_DATA.
109   @param[in]      Filename       Pointer to boot file name.
110   @param[in]      BlockSize      Pointer to required block size.
111   @param[in, out] BufferSize     Pointer to buffer size.
112 
113   @retval EFI_SUCCESS        Sucessfully obtained the size of file.
114   @retval EFI_NOT_FOUND      Parse the tftp ptions failed.
115   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
116   @retval Others             Has not obtained the size of the file.
117 
118 **/
119 EFI_STATUS
PxeBcMtftp6GetFileSize(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP6_CONFIG_DATA * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN OUT UINT64 * BufferSize)120 PxeBcMtftp6GetFileSize (
121   IN     PXEBC_PRIVATE_DATA           *Private,
122   IN     EFI_MTFTP6_CONFIG_DATA       *Config,
123   IN     UINT8                        *Filename,
124   IN     UINTN                        *BlockSize,
125   IN OUT UINT64                       *BufferSize
126   )
127 {
128   EFI_MTFTP6_PROTOCOL                 *Mtftp6;
129   EFI_MTFTP6_OPTION                   ReqOpt[2];
130   EFI_MTFTP6_PACKET                   *Packet;
131   EFI_MTFTP6_OPTION                   *Option;
132   UINT32                              PktLen;
133   UINT8                               OptBuf[128];
134   UINT32                              OptCnt;
135   EFI_STATUS                          Status;
136 
137   *BufferSize               = 0;
138   Status                    = EFI_DEVICE_ERROR;
139   Mtftp6                    = Private->Mtftp6;
140   Packet                    = NULL;
141   Option                    = NULL;
142   PktLen                    = 0;
143   OptCnt                    = 1;
144   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
145 
146   Status = Mtftp6->Configure (Mtftp6, Config);
147   if (EFI_ERROR (Status)) {
148     return Status;
149   }
150 
151   //
152   // Build the required options for get info.
153   //
154   ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_TSIZE_INDEX];
155   PxeBcUintnToAscDec (0, OptBuf, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
156   ReqOpt[0].ValueStr  = OptBuf;
157 
158   if (BlockSize != NULL) {
159     ReqOpt[1].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
160     ReqOpt[1].ValueStr  = (UINT8 *) (ReqOpt[0].ValueStr + AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1);
161     PxeBcUintnToAscDec (*BlockSize, ReqOpt[1].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX - (AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1));
162     OptCnt++;
163   }
164 
165   Status = Mtftp6->GetInfo (
166                      Mtftp6,
167                      NULL,
168                      Filename,
169                      NULL,
170                      (UINT8) OptCnt,
171                      ReqOpt,
172                      &PktLen,
173                      &Packet
174                      );
175   if (EFI_ERROR (Status)) {
176     if (Status == EFI_TFTP_ERROR) {
177       //
178       // Store the tftp error message into mode data and set the received flag.
179       //
180       Private->Mode.TftpErrorReceived   = TRUE;
181       Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
182       AsciiStrnCpyS (
183         Private->Mode.TftpError.ErrorString,
184         PXE_MTFTP_ERROR_STRING_LENGTH,
185         (CHAR8 *) Packet->Error.ErrorMessage,
186         PXE_MTFTP_ERROR_STRING_LENGTH - 1
187         );
188       Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1] = '\0';
189     }
190     goto ON_ERROR;
191   }
192 
193   //
194   // Parse the options in the reply packet.
195   //
196   OptCnt = 0;
197   Status = Mtftp6->ParseOptions (
198                      Mtftp6,
199                      PktLen,
200                      Packet,
201                      (UINT32 *) &OptCnt,
202                      &Option
203                      );
204   if (EFI_ERROR (Status)) {
205     goto ON_ERROR;
206   }
207 
208   //
209   // Parse out the value of "tsize" option.
210   //
211   Status = EFI_NOT_FOUND;
212   while (OptCnt != 0) {
213     if (AsciiStrnCmp ((CHAR8 *) Option[OptCnt - 1].OptionStr, "tsize", 5) == 0) {
214       *BufferSize = AsciiStrDecimalToUint64 ((CHAR8 *) (Option[OptCnt - 1].ValueStr));
215       Status      = EFI_SUCCESS;
216     }
217     OptCnt--;
218   }
219   FreePool (Option);
220 
221 ON_ERROR:
222   if (Packet != NULL) {
223     FreePool (Packet);
224   }
225   Mtftp6->Configure (Mtftp6, NULL);
226 
227   return Status;
228 }
229 
230 
231 /**
232   This function is to get data of a file using Tftp.
233 
234   @param[in]      Private        Pointer to PxeBc private data.
235   @param[in]      Config         Pointer to EFI_MTFTP6_CONFIG_DATA.
236   @param[in]      Filename       Pointer to boot file name.
237   @param[in]      BlockSize      Pointer to required block size.
238   @param[in]      BufferPtr      Pointer to buffer.
239   @param[in, out] BufferSize     Pointer to buffer size.
240   @param[in]      DontUseBuffer  Indicates whether with a receive buffer.
241 
242   @retval EFI_SUCCESS        Successfully read the data from the special file.
243   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
244   @retval Others             Read data from file failed.
245 
246 **/
247 EFI_STATUS
PxeBcMtftp6ReadFile(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP6_CONFIG_DATA * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize,IN BOOLEAN DontUseBuffer)248 PxeBcMtftp6ReadFile (
249   IN    PXEBC_PRIVATE_DATA            *Private,
250   IN     EFI_MTFTP6_CONFIG_DATA       *Config,
251   IN     UINT8                        *Filename,
252   IN     UINTN                        *BlockSize,
253   IN     UINT8                        *BufferPtr,
254   IN OUT UINT64                       *BufferSize,
255   IN     BOOLEAN                      DontUseBuffer
256   )
257 {
258   EFI_MTFTP6_PROTOCOL                 *Mtftp6;
259   EFI_MTFTP6_TOKEN                    Token;
260   EFI_MTFTP6_OPTION                   ReqOpt[1];
261   UINT32                              OptCnt;
262   UINT8                               OptBuf[128];
263   EFI_STATUS                          Status;
264 
265   Status                    = EFI_DEVICE_ERROR;
266   Mtftp6                    = Private->Mtftp6;
267   OptCnt                    = 0;
268   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
269 
270   Status = Mtftp6->Configure (Mtftp6, Config);
271   if (EFI_ERROR (Status)) {
272     return Status;
273   }
274 
275   if (BlockSize != NULL) {
276     ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
277     ReqOpt[0].ValueStr  = OptBuf;
278     PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
279     OptCnt++;
280   }
281 
282   Token.Event         = NULL;
283   Token.OverrideData  = NULL;
284   Token.Filename      = Filename;
285   Token.ModeStr       = NULL;
286   Token.OptionCount   = OptCnt;
287   Token.OptionList    = ReqOpt;
288   Token.Context       = Private;
289 
290   if (DontUseBuffer) {
291     Token.BufferSize  = 0;
292     Token.Buffer      = NULL;
293   } else {
294     Token.BufferSize  = *BufferSize;
295     Token.Buffer      = BufferPtr;
296   }
297 
298   Token.CheckPacket     = PxeBcMtftp6CheckPacket;
299   Token.TimeoutCallback = NULL;
300   Token.PacketNeeded    = NULL;
301 
302   Status = Mtftp6->ReadFile (Mtftp6, &Token);
303   //
304   // Get the real size of received buffer.
305   //
306   *BufferSize = Token.BufferSize;
307 
308   Mtftp6->Configure (Mtftp6, NULL);
309 
310   return Status;
311 }
312 
313 
314 /**
315   This function is used to write the data of a file using Tftp.
316 
317   @param[in]       Private        Pointer to PxeBc private data.
318   @param[in]       Config         Pointer to EFI_MTFTP6_CONFIG_DATA.
319   @param[in]       Filename       Pointer to boot file name.
320   @param[in]       Overwrite      Indicate whether with overwrite attribute.
321   @param[in]       BlockSize      Pointer to required block size.
322   @param[in]       BufferPtr      Pointer to buffer.
323   @param[in, out]  BufferSize     Pointer to buffer size.
324 
325   @retval EFI_SUCCESS        Successfully wrote the data into a special file.
326   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
327   @retval other              Write data into file failed.
328 
329 **/
330 EFI_STATUS
PxeBcMtftp6WriteFile(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP6_CONFIG_DATA * Config,IN UINT8 * Filename,IN BOOLEAN Overwrite,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize)331 PxeBcMtftp6WriteFile (
332   IN     PXEBC_PRIVATE_DATA           *Private,
333   IN     EFI_MTFTP6_CONFIG_DATA       *Config,
334   IN     UINT8                        *Filename,
335   IN     BOOLEAN                      Overwrite,
336   IN     UINTN                        *BlockSize,
337   IN     UINT8                        *BufferPtr,
338   IN OUT UINT64                       *BufferSize
339   )
340 {
341   EFI_MTFTP6_PROTOCOL                 *Mtftp6;
342   EFI_MTFTP6_TOKEN                    Token;
343   EFI_MTFTP6_OPTION                   ReqOpt[1];
344   UINT32                              OptCnt;
345   UINT8                               OptBuf[128];
346   EFI_STATUS                          Status;
347 
348   Status                    = EFI_DEVICE_ERROR;
349   Mtftp6                    = Private->Mtftp6;
350   OptCnt                    = 0;
351   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
352 
353   Status = Mtftp6->Configure (Mtftp6, Config);
354   if (EFI_ERROR (Status)) {
355     return Status;
356   }
357 
358   if (BlockSize != NULL) {
359     ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
360     ReqOpt[0].ValueStr  = OptBuf;
361     PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
362     OptCnt++;
363   }
364 
365   Token.Event           = NULL;
366   Token.OverrideData    = NULL;
367   Token.Filename        = Filename;
368   Token.ModeStr         = NULL;
369   Token.OptionCount     = OptCnt;
370   Token.OptionList      = ReqOpt;
371   Token.BufferSize      = *BufferSize;
372   Token.Buffer          = BufferPtr;
373   Token.CheckPacket     = PxeBcMtftp6CheckPacket;
374   Token.TimeoutCallback = NULL;
375   Token.PacketNeeded    = NULL;
376 
377   Status = Mtftp6->WriteFile (Mtftp6, &Token);
378   //
379   // Get the real size of transmitted buffer.
380   //
381   *BufferSize = Token.BufferSize;
382 
383   Mtftp6->Configure (Mtftp6, NULL);
384 
385   return Status;
386 }
387 
388 
389 /**
390   This function is to read the data (file) from a directory using Tftp.
391 
392   @param[in]       Private        Pointer to PxeBc private data.
393   @param[in]       Config         Pointer to EFI_MTFTP6_CONFIG_DATA.
394   @param[in]       Filename       Pointer to boot file name.
395   @param[in]       BlockSize      Pointer to required block size.
396   @param[in]       BufferPtr      Pointer to buffer.
397   @param[in, out]  BufferSize     Pointer to buffer size.
398   @param[in]       DontUseBuffer  Indicates whether to use a receive buffer.
399 
400   @retval EFI_SUCCESS        Successfully obtained the data from the file included in directory.
401   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
402   @retval Others             Operation failed.
403 
404 **/
405 EFI_STATUS
PxeBcMtftp6ReadDirectory(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP6_CONFIG_DATA * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize,IN BOOLEAN DontUseBuffer)406 PxeBcMtftp6ReadDirectory (
407   IN     PXEBC_PRIVATE_DATA            *Private,
408   IN     EFI_MTFTP6_CONFIG_DATA        *Config,
409   IN     UINT8                         *Filename,
410   IN     UINTN                         *BlockSize,
411   IN     UINT8                         *BufferPtr,
412   IN OUT UINT64                        *BufferSize,
413   IN     BOOLEAN                       DontUseBuffer
414   )
415 {
416   EFI_MTFTP6_PROTOCOL                  *Mtftp6;
417   EFI_MTFTP6_TOKEN                     Token;
418   EFI_MTFTP6_OPTION                    ReqOpt[1];
419   UINT32                               OptCnt;
420   UINT8                                OptBuf[128];
421   EFI_STATUS                           Status;
422 
423   Status                    = EFI_DEVICE_ERROR;
424   Mtftp6                    = Private->Mtftp6;
425   OptCnt                    = 0;
426   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
427 
428   Status = Mtftp6->Configure (Mtftp6, Config);
429   if (EFI_ERROR (Status)) {
430     return Status;
431   }
432 
433   if (BlockSize != NULL) {
434     ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
435     ReqOpt[0].ValueStr  = OptBuf;
436     PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
437     OptCnt++;
438   }
439 
440   Token.Event         = NULL;
441   Token.OverrideData  = NULL;
442   Token.Filename      = Filename;
443   Token.ModeStr       = NULL;
444   Token.OptionCount   = OptCnt;
445   Token.OptionList    = ReqOpt;
446   Token.Context       = Private;
447 
448   if (DontUseBuffer) {
449     Token.BufferSize  = 0;
450     Token.Buffer      = NULL;
451   } else {
452     Token.BufferSize  = *BufferSize;
453     Token.Buffer      = BufferPtr;
454   }
455 
456   Token.CheckPacket     = PxeBcMtftp6CheckPacket;
457   Token.TimeoutCallback = NULL;
458   Token.PacketNeeded    = NULL;
459 
460   Status = Mtftp6->ReadDirectory (Mtftp6, &Token);
461   //
462   // Get the real size of received buffer.
463   //
464   *BufferSize = Token.BufferSize;
465 
466   Mtftp6->Configure (Mtftp6, NULL);
467 
468   return Status;
469 }
470 
471 
472 /**
473   This is a callback function when packets are received or transmitted in Mtftp driver.
474 
475   A callback function that is provided by the caller to intercept
476   the EFI_MTFTP6_OPCODE_DATA or EFI_MTFTP4_OPCODE_DATA8 packets processed in the
477   EFI_MTFTP4_PROTOCOL.ReadFile() function, and alternatively to intercept
478   EFI_MTFTP4_OPCODE_OACK or EFI_MTFTP4_OPCODE_ERROR packets during a call to
479   EFI_MTFTP4_PROTOCOL.ReadFile(), WriteFile() or ReadDirectory().
480 
481   @param[in]  This           Pointer to EFI_MTFTP4_PROTOCOL.
482   @param[in]  Token          Pointer to EFI_MTFTP4_TOKEN.
483   @param[in]  PacketLen      Length of EFI_MTFTP4_PACKET.
484   @param[in]  Packet         Pointer to EFI_MTFTP4_PACKET to be checked.
485 
486   @retval EFI_SUCCESS    The current operation succeeeded.
487   @retval EFI_ABORTED    Abort the current transfer process.
488 
489 **/
490 EFI_STATUS
491 EFIAPI
PxeBcMtftp4CheckPacket(IN EFI_MTFTP4_PROTOCOL * This,IN EFI_MTFTP4_TOKEN * Token,IN UINT16 PacketLen,IN EFI_MTFTP4_PACKET * Packet)492 PxeBcMtftp4CheckPacket (
493   IN EFI_MTFTP4_PROTOCOL        *This,
494   IN EFI_MTFTP4_TOKEN           *Token,
495   IN UINT16                     PacketLen,
496   IN EFI_MTFTP4_PACKET          *Packet
497   )
498 {
499   PXEBC_PRIVATE_DATA                  *Private;
500   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
501   EFI_STATUS                          Status;
502 
503   Private   = (PXEBC_PRIVATE_DATA *) Token->Context;
504   Callback  = Private->PxeBcCallback;
505   Status    = EFI_SUCCESS;
506 
507   if (Packet->OpCode == EFI_MTFTP4_OPCODE_ERROR) {
508     //
509     // Store the tftp error message into mode data and set the received flag.
510     //
511     Private->Mode.TftpErrorReceived   = TRUE;
512     Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
513     AsciiStrnCpyS (
514       Private->Mode.TftpError.ErrorString,
515       PXE_MTFTP_ERROR_STRING_LENGTH,
516       (CHAR8 *) Packet->Error.ErrorMessage,
517       PXE_MTFTP_ERROR_STRING_LENGTH - 1
518       );
519     Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1] = '\0';
520   }
521 
522   if (Callback != NULL) {
523     //
524     // Callback to user if has when received any tftp packet.
525     //
526     Status = Callback->Callback (
527                         Callback,
528                         Private->Function,
529                         TRUE,
530                         PacketLen,
531                         (EFI_PXE_BASE_CODE_PACKET *) Packet
532                         );
533     if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
534       //
535       // User wants to abort current process if not EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE.
536       //
537       Status = EFI_ABORTED;
538     } else {
539       //
540       // User wants to continue current process if EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE.
541       //
542       Status = EFI_SUCCESS;
543     }
544   }
545 
546   return Status;
547 }
548 
549 
550 /**
551   This function is to get size of a file using Tftp.
552 
553   @param[in]      Private        Pointer to PxeBc private data.
554   @param[in]      Config         Pointer to EFI_MTFTP4_CONFIG_DATA.
555   @param[in]      Filename       Pointer to boot file name.
556   @param[in]      BlockSize      Pointer to required block size.
557   @param[in, out] BufferSize     Pointer to buffer size.
558 
559   @retval EFI_SUCCESS        Successfully obtained the size of file.
560   @retval EFI_NOT_FOUND      Parse the tftp options failed.
561   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
562   @retval Others             Did not obtain the size of the file.
563 
564 **/
565 EFI_STATUS
PxeBcMtftp4GetFileSize(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP4_CONFIG_DATA * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN OUT UINT64 * BufferSize)566 PxeBcMtftp4GetFileSize (
567   IN     PXEBC_PRIVATE_DATA         *Private,
568   IN     EFI_MTFTP4_CONFIG_DATA     *Config,
569   IN     UINT8                      *Filename,
570   IN     UINTN                      *BlockSize,
571   IN OUT UINT64                     *BufferSize
572   )
573 {
574   EFI_MTFTP4_PROTOCOL *Mtftp4;
575   EFI_MTFTP4_OPTION   ReqOpt[2];
576   EFI_MTFTP4_PACKET   *Packet;
577   EFI_MTFTP4_OPTION   *Option;
578   UINT32              PktLen;
579   UINT8               OptBuf[128];
580   UINT32              OptCnt;
581   EFI_STATUS          Status;
582 
583   *BufferSize               = 0;
584   Status                    = EFI_DEVICE_ERROR;
585   Mtftp4                    = Private->Mtftp4;
586   Packet                    = NULL;
587   Option                    = NULL;
588   PktLen                    = 0;
589   OptCnt                    = 1;
590   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
591 
592   Status = Mtftp4->Configure (Mtftp4, Config);
593   if (EFI_ERROR (Status)) {
594     return Status;
595   }
596 
597   //
598   // Build the required options for get info.
599   //
600   ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_TSIZE_INDEX];
601   PxeBcUintnToAscDec (0, OptBuf, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
602   ReqOpt[0].ValueStr  = OptBuf;
603 
604   if (BlockSize != NULL) {
605     ReqOpt[1].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
606     ReqOpt[1].ValueStr  = (UINT8 *) (ReqOpt[0].ValueStr + AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1);
607     PxeBcUintnToAscDec (*BlockSize, ReqOpt[1].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX - (AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1));
608     OptCnt++;
609   }
610 
611   Status = Mtftp4->GetInfo (
612                      Mtftp4,
613                      NULL,
614                      Filename,
615                      NULL,
616                      (UINT8) OptCnt,
617                      ReqOpt,
618                      &PktLen,
619                      &Packet
620                      );
621   if (EFI_ERROR (Status)) {
622     if (Status == EFI_TFTP_ERROR) {
623       //
624       // Store the tftp error message into mode data and set the received flag.
625       //
626       Private->Mode.TftpErrorReceived   = TRUE;
627       Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
628       AsciiStrnCpyS (
629         Private->Mode.TftpError.ErrorString,
630         PXE_MTFTP_ERROR_STRING_LENGTH,
631         (CHAR8 *) Packet->Error.ErrorMessage,
632         PXE_MTFTP_ERROR_STRING_LENGTH - 1
633         );
634       Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1] = '\0';
635     }
636     goto ON_ERROR;
637   }
638 
639   //
640   // Parse the options in the reply packet.
641   //
642   OptCnt = 0;
643   Status = Mtftp4->ParseOptions (
644                      Mtftp4,
645                      PktLen,
646                      Packet,
647                      (UINT32 *) &OptCnt,
648                      &Option
649                      );
650   if (EFI_ERROR (Status)) {
651     goto ON_ERROR;
652   }
653 
654   //
655   // Parse out the value of "tsize" option.
656   //
657   Status = EFI_NOT_FOUND;
658   while (OptCnt != 0) {
659     if (AsciiStrnCmp ((CHAR8 *) Option[OptCnt - 1].OptionStr, "tsize", 5) == 0) {
660       *BufferSize = AsciiStrDecimalToUint64 ((CHAR8 *) (Option[OptCnt - 1].ValueStr));
661       Status      = EFI_SUCCESS;
662     }
663     OptCnt--;
664   }
665   FreePool (Option);
666 
667 ON_ERROR:
668   if (Packet != NULL) {
669     FreePool (Packet);
670   }
671   Mtftp4->Configure (Mtftp4, NULL);
672 
673   return Status;
674 }
675 
676 
677 /**
678   This function is to read the data of a file using Tftp.
679 
680   @param[in]      Private        Pointer to PxeBc private data.
681   @param[in]      Config         Pointer to EFI_MTFTP4_CONFIG_DATA.
682   @param[in]      Filename       Pointer to boot file name.
683   @param[in]      BlockSize      Pointer to required block size.
684   @param[in]      BufferPtr      Pointer to buffer.
685   @param[in, out] BufferSize     Pointer to buffer size.
686   @param[in]      DontUseBuffer  Indicates whether to use a receive buffer.
687 
688   @retval EFI_SUCCESS        Successfully read the data from the special file.
689   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
690   @retval Others             Read data from file failed.
691 
692 **/
693 EFI_STATUS
PxeBcMtftp4ReadFile(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP4_CONFIG_DATA * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize,IN BOOLEAN DontUseBuffer)694 PxeBcMtftp4ReadFile (
695   IN     PXEBC_PRIVATE_DATA         *Private,
696   IN     EFI_MTFTP4_CONFIG_DATA     *Config,
697   IN     UINT8                      *Filename,
698   IN     UINTN                      *BlockSize,
699   IN     UINT8                      *BufferPtr,
700   IN OUT UINT64                     *BufferSize,
701   IN     BOOLEAN                    DontUseBuffer
702   )
703 {
704   EFI_MTFTP4_PROTOCOL *Mtftp4;
705   EFI_MTFTP4_TOKEN    Token;
706   EFI_MTFTP4_OPTION   ReqOpt[1];
707   UINT32              OptCnt;
708   UINT8               OptBuf[128];
709   EFI_STATUS          Status;
710 
711   Status                    = EFI_DEVICE_ERROR;
712   Mtftp4                    = Private->Mtftp4;
713   OptCnt                    = 0;
714   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
715 
716   Status = Mtftp4->Configure (Mtftp4, Config);
717   if (EFI_ERROR (Status)) {
718     return Status;
719   }
720 
721   if (BlockSize != NULL) {
722     ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
723     ReqOpt[0].ValueStr  = OptBuf;
724     PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
725     OptCnt++;
726   }
727 
728   Token.Event         = NULL;
729   Token.OverrideData  = NULL;
730   Token.Filename      = Filename;
731   Token.ModeStr       = NULL;
732   Token.OptionCount   = OptCnt;
733   Token.OptionList    = ReqOpt;
734   Token.Context       = Private;
735 
736   if (DontUseBuffer) {
737     Token.BufferSize  = 0;
738     Token.Buffer      = NULL;
739   } else {
740     Token.BufferSize  = *BufferSize;
741     Token.Buffer      = BufferPtr;
742   }
743 
744   Token.CheckPacket     = PxeBcMtftp4CheckPacket;
745   Token.TimeoutCallback = NULL;
746   Token.PacketNeeded    = NULL;
747 
748   Status = Mtftp4->ReadFile (Mtftp4, &Token);
749   //
750   // Get the real size of received buffer.
751   //
752   *BufferSize = Token.BufferSize;
753 
754   Mtftp4->Configure (Mtftp4, NULL);
755 
756   return Status;
757 }
758 
759 
760 /**
761   This function is to write the data of a file using Tftp.
762 
763   @param[in]       Private        Pointer to PxeBc private data.
764   @param[in]       Config         Pointer to EFI_MTFTP4_CONFIG_DATA.
765   @param[in]       Filename       Pointer to boot file name.
766   @param[in]       Overwrite      Indicates whether to use the overwrite attribute.
767   @param[in]       BlockSize      Pointer to required block size.
768   @param[in]       BufferPtr      Pointer to buffer.
769   @param[in, out]  BufferSize     Pointer to buffer size.
770 
771   @retval EFI_SUCCESS        Successfully write the data  into the special file.
772   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
773   @retval other              Write data into file failed.
774 
775 **/
776 EFI_STATUS
PxeBcMtftp4WriteFile(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP4_CONFIG_DATA * Config,IN UINT8 * Filename,IN BOOLEAN Overwrite,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize)777 PxeBcMtftp4WriteFile (
778   IN     PXEBC_PRIVATE_DATA         *Private,
779   IN     EFI_MTFTP4_CONFIG_DATA     *Config,
780   IN     UINT8                      *Filename,
781   IN     BOOLEAN                    Overwrite,
782   IN     UINTN                      *BlockSize,
783   IN     UINT8                      *BufferPtr,
784   IN OUT UINT64                     *BufferSize
785   )
786 {
787   EFI_MTFTP4_PROTOCOL *Mtftp4;
788   EFI_MTFTP4_TOKEN    Token;
789   EFI_MTFTP4_OPTION   ReqOpt[1];
790   UINT32              OptCnt;
791   UINT8               OptBuf[128];
792   EFI_STATUS          Status;
793 
794   Status                    = EFI_DEVICE_ERROR;
795   Mtftp4                    = Private->Mtftp4;
796   OptCnt                    = 0;
797   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
798 
799   Status  = Mtftp4->Configure (Mtftp4, Config);
800   if (EFI_ERROR (Status)) {
801     return Status;
802   }
803 
804   if (BlockSize != NULL) {
805     ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
806     ReqOpt[0].ValueStr  = OptBuf;
807     PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
808     OptCnt++;
809   }
810 
811   Token.Event           = NULL;
812   Token.OverrideData    = NULL;
813   Token.Filename        = Filename;
814   Token.ModeStr         = NULL;
815   Token.OptionCount     = OptCnt;
816   Token.OptionList      = ReqOpt;
817   Token.BufferSize      = *BufferSize;
818   Token.Buffer          = BufferPtr;
819   Token.CheckPacket     = PxeBcMtftp4CheckPacket;
820   Token.TimeoutCallback = NULL;
821   Token.PacketNeeded    = NULL;
822 
823   Status = Mtftp4->WriteFile (Mtftp4, &Token);
824   //
825   // Get the real size of transmitted buffer.
826   //
827   *BufferSize = Token.BufferSize;
828 
829   Mtftp4->Configure (Mtftp4, NULL);
830 
831   return Status;
832 }
833 
834 
835 /**
836   This function is to get data (file) from a directory using Tftp.
837 
838   @param[in]       Private        Pointer to PxeBc private data.
839   @param[in]       Config         Pointer to EFI_MTFTP4_CONFIG_DATA.
840   @param[in]       Filename       Pointer to boot file name.
841   @param[in]       BlockSize      Pointer to required block size.
842   @param[in]       BufferPtr      Pointer to buffer.
843   @param[in, out]  BufferSize     Pointer to buffer size.
844   @param[in]       DontUseBuffer  Indicates whether to use a receive buffer.
845 
846   @retval EFI_SUCCES         Successfully obtained the data from the file included in the directory.
847   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
848   @retval Others             Operation failed.
849 
850 **/
851 EFI_STATUS
PxeBcMtftp4ReadDirectory(IN PXEBC_PRIVATE_DATA * Private,IN EFI_MTFTP4_CONFIG_DATA * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize,IN BOOLEAN DontUseBuffer)852 PxeBcMtftp4ReadDirectory (
853   IN     PXEBC_PRIVATE_DATA            *Private,
854   IN     EFI_MTFTP4_CONFIG_DATA        *Config,
855   IN     UINT8                         *Filename,
856   IN     UINTN                         *BlockSize,
857   IN     UINT8                         *BufferPtr,
858   IN OUT UINT64                        *BufferSize,
859   IN     BOOLEAN                       DontUseBuffer
860   )
861 {
862   EFI_MTFTP4_PROTOCOL *Mtftp4;
863   EFI_MTFTP4_TOKEN    Token;
864   EFI_MTFTP4_OPTION   ReqOpt[1];
865   UINT32              OptCnt;
866   UINT8               OptBuf[128];
867   EFI_STATUS          Status;
868 
869   Status                    = EFI_DEVICE_ERROR;
870   Mtftp4                    = Private->Mtftp4;
871   OptCnt                    = 0;
872   Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;
873 
874   Status = Mtftp4->Configure (Mtftp4, Config);
875   if (EFI_ERROR (Status)) {
876     return Status;
877   }
878 
879   if (BlockSize != NULL) {
880     ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
881     ReqOpt[0].ValueStr  = OptBuf;
882     PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
883     OptCnt++;
884   }
885 
886   Token.Event         = NULL;
887   Token.OverrideData  = NULL;
888   Token.Filename      = Filename;
889   Token.ModeStr       = NULL;
890   Token.OptionCount   = OptCnt;
891   Token.OptionList    = ReqOpt;
892   Token.Context       = Private;
893 
894   if (DontUseBuffer) {
895     Token.BufferSize  = 0;
896     Token.Buffer      = NULL;
897   } else {
898     Token.BufferSize  = *BufferSize;
899     Token.Buffer      = BufferPtr;
900   }
901 
902   Token.CheckPacket     = PxeBcMtftp4CheckPacket;
903   Token.TimeoutCallback = NULL;
904   Token.PacketNeeded    = NULL;
905 
906   Status = Mtftp4->ReadDirectory (Mtftp4, &Token);
907   //
908   // Get the real size of received buffer.
909   //
910   *BufferSize = Token.BufferSize;
911 
912   Mtftp4->Configure (Mtftp4, NULL);
913 
914   return Status;
915 }
916 
917 
918 /**
919   This function is wrapper to get the file size using TFTP.
920 
921   @param[in]      Private        Pointer to PxeBc private data.
922   @param[in]      Config         Pointer to configure data.
923   @param[in]      Filename       Pointer to boot file name.
924   @param[in]      BlockSize      Pointer to required block size.
925   @param[in, out] BufferSize     Pointer to buffer size.
926 
927   @retval EFI_SUCCESS        Successfully obtained the size of file.
928   @retval EFI_NOT_FOUND      Parse the tftp options failed.
929   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
930   @retval Others             Did not obtain the size of the file.
931 
932 **/
933 EFI_STATUS
PxeBcTftpGetFileSize(IN PXEBC_PRIVATE_DATA * Private,IN VOID * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN OUT UINT64 * BufferSize)934 PxeBcTftpGetFileSize (
935   IN     PXEBC_PRIVATE_DATA         *Private,
936   IN     VOID                       *Config,
937   IN     UINT8                      *Filename,
938   IN     UINTN                      *BlockSize,
939   IN OUT UINT64                     *BufferSize
940   )
941 {
942   if (Private->PxeBc.Mode->UsingIpv6) {
943     return PxeBcMtftp6GetFileSize (
944              Private,
945              (EFI_MTFTP6_CONFIG_DATA *) Config,
946              Filename,
947              BlockSize,
948              BufferSize
949              );
950   } else {
951     return PxeBcMtftp4GetFileSize (
952              Private,
953              (EFI_MTFTP4_CONFIG_DATA *) Config,
954              Filename,
955              BlockSize,
956              BufferSize
957              );
958   }
959 }
960 
961 
962 /**
963   This function is a wrapper to get file using TFTP.
964 
965   @param[in]      Private        Pointer to PxeBc private data.
966   @param[in]      Config         Pointer to config data.
967   @param[in]      Filename       Pointer to boot file name.
968   @param[in]      BlockSize      Pointer to required block size.
969   @param[in]      BufferPtr      Pointer to buffer.
970   @param[in, out] BufferSize     Pointer to buffer size.
971   @param[in]      DontUseBuffer  Indicates whether to use a receive buffer.
972 
973   @retval EFI_SUCCESS        Sucessfully read the data from the special file.
974   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
975   @retval Others             Read data from file failed.
976 
977 **/
978 EFI_STATUS
PxeBcTftpReadFile(IN PXEBC_PRIVATE_DATA * Private,IN VOID * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize,IN BOOLEAN DontUseBuffer)979 PxeBcTftpReadFile (
980   IN     PXEBC_PRIVATE_DATA         *Private,
981   IN     VOID                       *Config,
982   IN     UINT8                      *Filename,
983   IN     UINTN                      *BlockSize,
984   IN     UINT8                      *BufferPtr,
985   IN OUT UINT64                     *BufferSize,
986   IN     BOOLEAN                    DontUseBuffer
987   )
988 {
989   if (Private->PxeBc.Mode->UsingIpv6) {
990     return PxeBcMtftp6ReadFile (
991              Private,
992              (EFI_MTFTP6_CONFIG_DATA *) Config,
993              Filename,
994              BlockSize,
995              BufferPtr,
996              BufferSize,
997              DontUseBuffer
998              );
999   } else {
1000     return PxeBcMtftp4ReadFile (
1001              Private,
1002              (EFI_MTFTP4_CONFIG_DATA *) Config,
1003              Filename,
1004              BlockSize,
1005              BufferPtr,
1006              BufferSize,
1007              DontUseBuffer
1008              );
1009   }
1010 }
1011 
1012 
1013 /**
1014   This function is a wrapper to write file using TFTP.
1015 
1016   @param[in]       Private        Pointer to PxeBc private data.
1017   @param[in]       Config         Pointer to config data.
1018   @param[in]       Filename       Pointer to boot file name.
1019   @param[in]       Overwrite      Indicate whether with overwrite attribute.
1020   @param[in]       BlockSize      Pointer to required block size.
1021   @param[in]       BufferPtr      Pointer to buffer.
1022   @param[in, out]  BufferSize     Pointer to buffer size.
1023 
1024   @retval EFI_SUCCESS        Successfully wrote the data into a special file.
1025   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
1026   @retval other              Write data into file failed.
1027 
1028 **/
1029 EFI_STATUS
PxeBcTftpWriteFile(IN PXEBC_PRIVATE_DATA * Private,IN VOID * Config,IN UINT8 * Filename,IN BOOLEAN Overwrite,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize)1030 PxeBcTftpWriteFile (
1031   IN     PXEBC_PRIVATE_DATA         *Private,
1032   IN     VOID                       *Config,
1033   IN     UINT8                      *Filename,
1034   IN     BOOLEAN                    Overwrite,
1035   IN     UINTN                      *BlockSize,
1036   IN     UINT8                      *BufferPtr,
1037   IN OUT UINT64                     *BufferSize
1038   )
1039 {
1040   if (Private->PxeBc.Mode->UsingIpv6) {
1041     return PxeBcMtftp6WriteFile (
1042              Private,
1043              (EFI_MTFTP6_CONFIG_DATA *) Config,
1044              Filename,
1045              Overwrite,
1046              BlockSize,
1047              BufferPtr,
1048              BufferSize
1049              );
1050   } else {
1051     return PxeBcMtftp4WriteFile (
1052              Private,
1053              (EFI_MTFTP4_CONFIG_DATA *) Config,
1054              Filename,
1055              Overwrite,
1056              BlockSize,
1057              BufferPtr,
1058              BufferSize
1059              );
1060   }
1061 }
1062 
1063 
1064 /**
1065   This function is a wrapper to get the data (file) from a directory using TFTP.
1066 
1067   @param[in]       Private        Pointer to PxeBc private data.
1068   @param[in]       Config         Pointer to config data.
1069   @param[in]       Filename       Pointer to boot file name.
1070   @param[in]       BlockSize      Pointer to required block size.
1071   @param[in]       BufferPtr      Pointer to buffer.
1072   @param[in, out]  BufferSize     Pointer to buffer size.
1073   @param[in]       DontUseBuffer  Indicatse whether to use a receive buffer.
1074 
1075   @retval EFI_SUCCES         Successfully obtained the data from the file included in the directory.
1076   @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
1077   @retval Others             Operation failed.
1078 
1079 **/
1080 EFI_STATUS
PxeBcTftpReadDirectory(IN PXEBC_PRIVATE_DATA * Private,IN VOID * Config,IN UINT8 * Filename,IN UINTN * BlockSize,IN UINT8 * BufferPtr,IN OUT UINT64 * BufferSize,IN BOOLEAN DontUseBuffer)1081 PxeBcTftpReadDirectory (
1082   IN     PXEBC_PRIVATE_DATA            *Private,
1083   IN     VOID                          *Config,
1084   IN     UINT8                         *Filename,
1085   IN     UINTN                         *BlockSize,
1086   IN     UINT8                         *BufferPtr,
1087   IN OUT UINT64                        *BufferSize,
1088   IN     BOOLEAN                       DontUseBuffer
1089   )
1090 {
1091   if (Private->PxeBc.Mode->UsingIpv6) {
1092     return PxeBcMtftp6ReadDirectory (
1093              Private,
1094              (EFI_MTFTP6_CONFIG_DATA *) Config,
1095              Filename,
1096              BlockSize,
1097              BufferPtr,
1098              BufferSize,
1099              DontUseBuffer
1100              );
1101   } else {
1102     return PxeBcMtftp4ReadDirectory (
1103              Private,
1104              (EFI_MTFTP4_CONFIG_DATA *) Config,
1105              Filename,
1106              BlockSize,
1107              BufferPtr,
1108              BufferSize,
1109              DontUseBuffer
1110              );
1111   }
1112 }
1113 
1114