214ac44745c7843c57197ebddbfcb52f658bc5d7
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Impl.c
1 /** @file\r
2 \r
3 Copyright (c) 2006 - 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   Mtftp4Impl.c\r
15 \r
16 Abstract:\r
17 \r
18   Interface routine for Mtftp4\r
19 \r
20 \r
21 **/\r
22 \r
23 #include "Mtftp4Impl.h"\r
24 \r
25 STATIC\r
26 EFI_STATUS\r
27 EFIAPI\r
28 EfiMtftp4ReadFile (\r
29   IN EFI_MTFTP4_PROTOCOL    *This,\r
30   IN EFI_MTFTP4_TOKEN       *Token\r
31   );\r
32 \r
33 \r
34 /**\r
35   Get the current operation parameter for the MTFTP session\r
36 \r
37   @param  This                   The MTFTP protocol instance\r
38   @param  ModeData               The MTFTP mode data\r
39 \r
40   @retval EFI_INVALID_PARAMETER  This or ModeData is NULL\r
41   @retval EFI_SUCCESS            The operation parameter is saved in ModeData\r
42 \r
43 **/\r
44 STATIC\r
45 EFI_STATUS\r
46 EFIAPI\r
47 EfiMtftp4GetModeData (\r
48   IN EFI_MTFTP4_PROTOCOL    *This,\r
49   OUT EFI_MTFTP4_MODE_DATA  *ModeData\r
50   )\r
51 {\r
52   MTFTP4_PROTOCOL  *Instance;\r
53   EFI_TPL          OldTpl;\r
54 \r
55   if ((This == NULL) || (ModeData == NULL)) {\r
56     return EFI_INVALID_PARAMETER;\r
57   }\r
58 \r
59   OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
60 \r
61   Instance                         = MTFTP4_PROTOCOL_FROM_THIS (This);\r
62   CopyMem(&ModeData->ConfigData, &Instance->Config, sizeof (Instance->Config));\r
63   ModeData->SupportedOptionCount   = MTFTP4_SUPPORTED_OPTIONS;\r
64   ModeData->SupportedOptoins       = (UINT8 **) mMtftp4SupportedOptions;\r
65   ModeData->UnsupportedOptionCount = 0;\r
66   ModeData->UnsupportedOptoins     = NULL;\r
67 \r
68   NET_RESTORE_TPL (OldTpl);\r
69 \r
70   return EFI_SUCCESS;\r
71 }\r
72 \r
73 \r
74 /**\r
75   Clean up the MTFTP session to get ready for new operation.\r
76 \r
77   @param  Instance               The MTFTP session to clean up\r
78   @param  Result                 The result to return to the caller who initiated\r
79                                  the operation.\r
80 \r
81   @return None\r
82 \r
83 **/\r
84 VOID\r
85 Mtftp4CleanOperation (\r
86   IN MTFTP4_PROTOCOL        *Instance,\r
87   IN EFI_STATUS             Result\r
88   )\r
89 {\r
90   NET_LIST_ENTRY            *Entry;\r
91   NET_LIST_ENTRY            *Next;\r
92   MTFTP4_BLOCK_RANGE        *Block;\r
93   EFI_MTFTP4_TOKEN          *Token;\r
94 \r
95   //\r
96   // Free various resources.\r
97   //\r
98   Token = Instance->Token;\r
99 \r
100   if (Token != NULL) {\r
101     Token->Status = Result;\r
102 \r
103     if (Token->Event != NULL) {\r
104       gBS->SignalEvent (Token->Event);\r
105     }\r
106 \r
107     Instance->Token = NULL;\r
108   }\r
109 \r
110   ASSERT (Instance->UnicastPort != NULL);\r
111   UdpIoCleanPort (Instance->UnicastPort);\r
112 \r
113   if (Instance->LastPacket != NULL) {\r
114     NetbufFree (Instance->LastPacket);\r
115     Instance->LastPacket = NULL;\r
116   }\r
117 \r
118   if (Instance->McastUdpPort != NULL) {\r
119     UdpIoFreePort (Instance->McastUdpPort);\r
120     Instance->McastUdpPort = NULL;\r
121   }\r
122 \r
123   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->Blocks) {\r
124     Block = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);\r
125     NetListRemoveEntry (Entry);\r
126     NetFreePool (Block);\r
127   }\r
128 \r
129   NetZeroMem (&Instance->RequestOption, sizeof (MTFTP4_OPTION));\r
130 \r
131   Instance->Operation     = 0;\r
132 \r
133   Instance->BlkSize       = MTFTP4_DEFAULT_BLKSIZE;\r
134   Instance->LastBlock     = 0;\r
135   Instance->ServerIp      = 0;\r
136   Instance->ListeningPort = 0;\r
137   Instance->ConnectedPort = 0;\r
138   Instance->Gateway       = 0;\r
139   Instance->PacketToLive  = 0;\r
140   Instance->MaxRetry      = 0;\r
141   Instance->CurRetry      = 0;\r
142   Instance->Timeout       = 0;\r
143   Instance->McastIp       = 0;\r
144   Instance->McastPort     = 0;\r
145   Instance->Master        = TRUE;\r
146 }\r
147 \r
148 \r
149 /**\r
150   Configure the MTFTP session for new operation or reset the current\r
151   operation if ConfigData is NULL.\r
152 \r
153   @param  This                   The MTFTP session to configure\r
154   @param  ConfigData             The configure parameters\r
155 \r
156   @retval EFI_INVALID_PARAMETER  Some of the parameter is invalid.\r
157   @retval EFI_ACCESS_DENIED      There is pending operation\r
158   @retval EFI_SUCCESS            The instance is configured for operation.\r
159 \r
160 **/\r
161 STATIC\r
162 EFI_STATUS\r
163 EFIAPI\r
164 EfiMtftp4Configure (\r
165   IN EFI_MTFTP4_PROTOCOL    *This,\r
166   IN EFI_MTFTP4_CONFIG_DATA *ConfigData\r
167   )\r
168 {\r
169   MTFTP4_PROTOCOL           *Instance;\r
170   EFI_TPL                   OldTpl;\r
171   IP4_ADDR                  Ip;\r
172   IP4_ADDR                  Netmask;\r
173   IP4_ADDR                  Gateway;\r
174   IP4_ADDR                  ServerIp;\r
175 \r
176   if (This == NULL) {\r
177     return EFI_INVALID_PARAMETER;\r
178   }\r
179 \r
180   Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
181 \r
182   if (ConfigData == NULL) {\r
183     //\r
184     // Reset the operation if ConfigData is NULL\r
185     //\r
186     OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
187 \r
188     Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
189     NetZeroMem (&Instance->Config, sizeof (EFI_MTFTP4_CONFIG_DATA));\r
190     Instance->State = MTFTP4_STATE_UNCONFIGED;\r
191 \r
192     NET_RESTORE_TPL (OldTpl);\r
193 \r
194   } else {\r
195     //\r
196     // Configure the parameters for new operation.\r
197     //\r
198     NetCopyMem (&Ip, &ConfigData->StationIp, sizeof (IP4_ADDR));\r
199     NetCopyMem (&Netmask, &ConfigData->SubnetMask, sizeof (IP4_ADDR));\r
200     NetCopyMem (&Gateway, &ConfigData->GatewayIp, sizeof (IP4_ADDR));\r
201     NetCopyMem (&ServerIp, &ConfigData->ServerIp, sizeof (IP4_ADDR));\r
202 \r
203     Ip       = NTOHL (Ip);\r
204     Netmask  = NTOHL (Netmask);\r
205     Gateway  = NTOHL (Gateway);\r
206     ServerIp = NTOHL (ServerIp);\r
207 \r
208     if (!Ip4IsUnicast (ServerIp, 0)) {\r
209       return EFI_INVALID_PARAMETER;\r
210     }\r
211 \r
212     if (!ConfigData->UseDefaultSetting &&\r
213        ((!IP4_IS_VALID_NETMASK (Netmask) || !Ip4IsUnicast (Ip, Netmask)))) {\r
214 \r
215       return EFI_INVALID_PARAMETER;\r
216     }\r
217 \r
218     if ((Gateway != 0) &&\r
219        (!IP4_NET_EQUAL (Gateway, Ip, Netmask) || !Ip4IsUnicast (Gateway, Netmask))) {\r
220 \r
221       return EFI_INVALID_PARAMETER;\r
222     }\r
223 \r
224     OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
225 \r
226     if ((Instance->State == MTFTP4_STATE_CONFIGED) && (Instance->Operation != 0)) {\r
227       NET_RESTORE_TPL (OldTpl);\r
228       return EFI_ACCESS_DENIED;\r
229     }\r
230 \r
231     CopyMem(&Instance->Config, ConfigData, sizeof (*ConfigData));;\r
232     Instance->State = MTFTP4_STATE_CONFIGED;\r
233 \r
234     NET_RESTORE_TPL (OldTpl);\r
235   }\r
236 \r
237   return EFI_SUCCESS;\r
238 }\r
239 \r
240 \r
241 /**\r
242   Check packet for GetInfo. GetInfo is implemented with EfiMtftp4ReadFile.\r
243   It use Mtftp4GetInfoCheckPacket to inspect the first packet from server,\r
244   then abort the session.\r
245 \r
246   @param  This                   The MTFTP4 protocol instance\r
247   @param  Token                  The user's token\r
248   @param  PacketLen              The length of the packet\r
249   @param  Packet                 The received packet.\r
250 \r
251   @retval EFI_ABORTED            Abort the ReadFile operation and return.\r
252 \r
253 **/\r
254 STATIC\r
255 EFI_STATUS\r
256 Mtftp4GetInfoCheckPacket (\r
257   IN EFI_MTFTP4_PROTOCOL    *This,\r
258   IN EFI_MTFTP4_TOKEN       *Token,\r
259   IN UINT16                 PacketLen,\r
260   IN EFI_MTFTP4_PACKET      *Packet\r
261   )\r
262 {\r
263   MTFTP4_GETINFO_STATE      *State;\r
264   EFI_STATUS                Status;\r
265   UINT16                    OpCode;\r
266 \r
267   State   = (MTFTP4_GETINFO_STATE *) Token->Context;\r
268   OpCode   = NTOHS (Packet->OpCode);\r
269 \r
270   //\r
271   // Set the GetInfo's return status according to the OpCode.\r
272   //\r
273   switch (OpCode) {\r
274   case EFI_MTFTP4_OPCODE_ERROR:\r
275     State->Status = EFI_TFTP_ERROR;\r
276     break;\r
277 \r
278   case EFI_MTFTP4_OPCODE_OACK:\r
279     State->Status = EFI_SUCCESS;\r
280     break;\r
281 \r
282   default:\r
283     State->Status = EFI_PROTOCOL_ERROR;\r
284   }\r
285 \r
286   //\r
287   // Allocate buffer then copy the packet over. Use gBS->AllocatePool\r
288   // in case NetAllocatePool will implements something tricky.\r
289   //\r
290   Status = gBS->AllocatePool (EfiBootServicesData, PacketLen, (VOID **) State->Packet);\r
291 \r
292   if (EFI_ERROR (Status)) {\r
293     State->Status = EFI_OUT_OF_RESOURCES;\r
294     return EFI_ABORTED;\r
295   }\r
296 \r
297   *(State->PacketLen) = PacketLen;\r
298   NetCopyMem (*(State->Packet), Packet, PacketLen);\r
299 \r
300   return EFI_ABORTED;\r
301 }\r
302 \r
303 \r
304 /**\r
305   Get the information of the download from the server. It is implemented\r
306   with EfiMtftp4ReadFile: build a token, then pass it to EfiMtftp4ReadFile.\r
307   In its check packet callback abort the opertions.\r
308 \r
309   @param  This                   The MTFTP protocol instance\r
310   @param  OverrideData           The MTFTP override data\r
311   @param  Filename               The file to get information\r
312   @param  ModeStr                The mode to use\r
313   @param  OptionCount            The number of options to append\r
314   @param  OptionList             The options to append\r
315   @param  PacketLength           The variable to receive the packet length\r
316   @param  Packet                 The variable to receive the packet.\r
317 \r
318   @retval EFI_INVALID_PARAMETER  The parameter is invaid\r
319   @retval EFI_SUCCESS            The information is got\r
320   @retval Others                 Failed to get the information.\r
321 \r
322 **/\r
323 STATIC\r
324 EFI_STATUS\r
325 EFIAPI\r
326 EfiMtftp4GetInfo (\r
327   IN EFI_MTFTP4_PROTOCOL      *This,\r
328   IN EFI_MTFTP4_OVERRIDE_DATA *OverrideData,        OPTIONAL\r
329   IN UINT8                    *Filename,\r
330   IN UINT8                    *ModeStr,             OPTIONAL\r
331   IN UINT8                    OptionCount,\r
332   IN EFI_MTFTP4_OPTION        *OptionList,\r
333   OUT UINT32                  *PacketLength,\r
334   OUT EFI_MTFTP4_PACKET       **Packet OPTIONAL\r
335   )\r
336 {\r
337   EFI_MTFTP4_TOKEN          Token;\r
338   MTFTP4_GETINFO_STATE      State;\r
339   EFI_STATUS                Status;\r
340 \r
341   if ((This == NULL) || (Filename == NULL) || (PacketLength == NULL) ||\r
342       (OptionCount && (OptionList == NULL))) {\r
343     return EFI_INVALID_PARAMETER;\r
344   }\r
345 \r
346   if (Packet != NULL) {\r
347     *Packet = NULL;\r
348   }\r
349 \r
350   *PacketLength         = 0;\r
351   State.Packet          = Packet;\r
352   State.PacketLen       = PacketLength;\r
353   State.Status          = EFI_SUCCESS;\r
354 \r
355   //\r
356   // Fill in the Token to issue an synchronous ReadFile operation\r
357   //\r
358   Token.Status          = EFI_SUCCESS;\r
359   Token.Event           = NULL;\r
360   Token.OverrideData    = OverrideData;\r
361   Token.Filename        = Filename;\r
362   Token.ModeStr         = ModeStr;\r
363   Token.OptionCount     = OptionCount;\r
364   Token.OptionList      = OptionList;\r
365   Token.BufferSize      = 0;\r
366   Token.Buffer          = NULL;\r
367   Token.Context         = &State;\r
368   Token.CheckPacket     = Mtftp4GetInfoCheckPacket;\r
369   Token.TimeoutCallback = NULL;\r
370   Token.PacketNeeded    = NULL;\r
371 \r
372   Status                = EfiMtftp4ReadFile (This, &Token);\r
373 \r
374   if (EFI_ABORTED == Status) {\r
375     return State.Status;\r
376   }\r
377 \r
378   return Status;\r
379 }\r
380 \r
381 \r
382 /**\r
383   Parse the packet into an array of options. The OptionList is allocated\r
384   by this function, and caller should free it when used.\r
385 \r
386   @param  This                   The MTFTP protocol instance\r
387   @param  PacketLen              The length of the packet\r
388   @param  Packet                 The packet to parse\r
389   @param  OptionCount            The size of the OptionList array allocated.\r
390   @param  OptionList             The allocated option array to save the option\r
391                                  addresses.\r
392 \r
393   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
394   @retval EFI_NOT_FOUND          There is no valid option in the packet\r
395   @retval EFI_SUCCESS            The packet is parsed.\r
396 \r
397 **/\r
398 STATIC\r
399 EFI_STATUS\r
400 EFIAPI\r
401 EfiMtftp4ParseOptions (\r
402   IN EFI_MTFTP4_PROTOCOL    *This,\r
403   IN UINT32                 PacketLen,\r
404   IN EFI_MTFTP4_PACKET      *Packet,\r
405   IN OUT UINT32             *OptionCount,\r
406   OUT EFI_MTFTP4_OPTION     **OptionList          OPTIONAL\r
407   )\r
408 {\r
409   EFI_STATUS                Status;\r
410 \r
411   if ((This == NULL) || (PacketLen < MTFTP4_OPCODE_LEN) ||\r
412       (Packet == NULL) || (OptionCount == NULL)) {\r
413 \r
414     return EFI_INVALID_PARAMETER;\r
415   }\r
416 \r
417   Status = Mtftp4ExtractOptions (Packet, PacketLen, OptionCount, OptionList);\r
418 \r
419   if (EFI_ERROR (Status)) {\r
420     return Status;\r
421   }\r
422 \r
423   if (*OptionCount == 0) {\r
424     return EFI_NOT_FOUND;\r
425   }\r
426 \r
427   return EFI_SUCCESS;\r
428 }\r
429 \r
430 \r
431 /**\r
432   Check whether the override data is valid. It will first\r
433   validate whether the server is a valid unicast. If a gateway\r
434   is provided in the Override, it also check that it is a\r
435   unicast on the connected network.\r
436 \r
437   @param  Instance               The MTFTP instance\r
438   @param  Override               The override data to validate.\r
439 \r
440   @return TRUE if the override data is valid, otherwise FALSE.\r
441 \r
442 **/\r
443 STATIC\r
444 BOOLEAN\r
445 Mtftp4OverrideValid (\r
446   IN MTFTP4_PROTOCOL          *Instance,\r
447   IN EFI_MTFTP4_OVERRIDE_DATA *Override\r
448   )\r
449 {\r
450   EFI_MTFTP4_CONFIG_DATA    *Config;\r
451   IP4_ADDR                  Ip;\r
452   IP4_ADDR                  Netmask;\r
453   IP4_ADDR                  Gateway;\r
454 \r
455   NetCopyMem (&Ip, &Override->ServerIp, sizeof (IP4_ADDR));\r
456   if (!Ip4IsUnicast (NTOHL (Ip), 0)) {\r
457     return FALSE;\r
458   }\r
459 \r
460   Config = &Instance->Config;\r
461 \r
462   NetCopyMem (&Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));\r
463   Gateway = NTOHL (Gateway);\r
464 \r
465   if (!Config->UseDefaultSetting && (Gateway != 0)) {\r
466     NetCopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));\r
467     NetCopyMem (&Ip, &Config->StationIp, sizeof (IP4_ADDR));\r
468 \r
469     Netmask = NTOHL (Netmask);\r
470     Ip      = NTOHL (Ip);\r
471 \r
472     if (!Ip4IsUnicast (Gateway, Netmask) || !IP4_NET_EQUAL (Gateway, Ip, Netmask)) {\r
473       return FALSE;\r
474     }\r
475   }\r
476 \r
477   return TRUE;\r
478 }\r
479 \r
480 \r
481 /**\r
482   Poll the UDP to get the IP4 default address, which may be retrieved\r
483   by DHCP. The default time out value is 5 seconds. If IP has retrieved\r
484   the default address, the UDP is reconfigured.\r
485 \r
486   @param  Instance               The Mtftp instance\r
487   @param  UdpPort                The UDP port to poll\r
488   @param  UdpCfgData             The UDP configure data to reconfigure the UDP\r
489                                  port.\r
490 \r
491   @return TRUE if the default address is retrieved and UDP is reconfigured.\r
492   @return Otherwise FALSE.\r
493 \r
494 **/\r
495 BOOLEAN\r
496 Mtftp4GetMapping (\r
497   IN MTFTP4_PROTOCOL        *Instance,\r
498   IN UDP_IO_PORT            *UdpPort,\r
499   IN EFI_UDP4_CONFIG_DATA   *UdpCfgData\r
500   )\r
501 {\r
502   MTFTP4_SERVICE            *Service;\r
503   EFI_IP4_MODE_DATA         Ip4Mode;\r
504   EFI_UDP4_PROTOCOL         *Udp;\r
505   EFI_STATUS                Status;\r
506 \r
507   ASSERT (Instance->Config.UseDefaultSetting);\r
508 \r
509   Service = Instance->Service;\r
510   Udp     = UdpPort->Udp;\r
511 \r
512   Status = gBS->SetTimer (\r
513                   Service->TimerToGetMap,\r
514                   TimerRelative,\r
515                   MTFTP4_TIME_TO_GETMAP * TICKS_PER_SECOND\r
516                   );\r
517   if (EFI_ERROR (Status)) {\r
518     return FALSE;\r
519   }\r
520 \r
521   while (!EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {\r
522     Udp->Poll (Udp);\r
523 \r
524     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&\r
525         Ip4Mode.IsConfigured) {\r
526 \r
527       Udp->Configure (Udp, NULL);\r
528       return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);\r
529     }\r
530   }\r
531 \r
532   return FALSE;\r
533 }\r
534 \r
535 \r
536 /**\r
537   Configure the UDP port for unicast receiving.\r
538 \r
539   @param  UdpIo                  The UDP port\r
540   @param  Instance               The MTFTP session\r
541 \r
542   @retval EFI_SUCCESS            The UDP port is successfully configured for the\r
543                                  session to unicast receive.\r
544 \r
545 **/\r
546 STATIC\r
547 EFI_STATUS\r
548 Mtftp4ConfigUnicastPort (\r
549   IN UDP_IO_PORT            *UdpIo,\r
550   IN MTFTP4_PROTOCOL        *Instance\r
551   )\r
552 {\r
553   EFI_MTFTP4_CONFIG_DATA    *Config;\r
554   EFI_UDP4_CONFIG_DATA      UdpConfig;\r
555   EFI_STATUS                Status;\r
556   IP4_ADDR                  Ip;\r
557 \r
558   Config = &Instance->Config;\r
559 \r
560   UdpConfig.AcceptBroadcast    = FALSE;\r
561   UdpConfig.AcceptPromiscuous  = FALSE;\r
562   UdpConfig.AcceptAnyPort      = FALSE;\r
563   UdpConfig.AllowDuplicatePort = FALSE;\r
564   UdpConfig.TypeOfService      = 0;\r
565   UdpConfig.TimeToLive         = 64;\r
566   UdpConfig.DoNotFragment      = FALSE;\r
567   UdpConfig.ReceiveTimeout     = 0;\r
568   UdpConfig.TransmitTimeout    = 0;\r
569   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;\r
570   UdpConfig.StationAddress     = Config->StationIp;\r
571   UdpConfig.SubnetMask         = Config->SubnetMask;\r
572   UdpConfig.StationPort        = 0;\r
573   UdpConfig.RemotePort         = 0;\r
574 \r
575   Ip = HTONL (Instance->ServerIp);\r
576   NetCopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
577 \r
578   Status = UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfig);\r
579 \r
580   if ((Status == EFI_NO_MAPPING) && Mtftp4GetMapping (Instance, UdpIo, &UdpConfig)) {\r
581     return EFI_SUCCESS;\r
582   }\r
583 \r
584   return Status;\r
585 }\r
586 \r
587 \r
588 /**\r
589   Start the MTFTP session to do the operation, such as read file,\r
590   write file, and read directory.\r
591 \r
592   @param  This                   The MTFTP session\r
593   @param  Token                  The token than encapsues the user's request.\r
594   @param  Operation              The operation to do\r
595 \r
596   @retval EFI_INVALID_PARAMETER  Some of the parameters are invalid.\r
597   @retval EFI_NOT_STARTED        The MTFTP session hasn't been configured.\r
598   @retval EFI_ALREADY_STARTED    There is pending operation for the session.\r
599   @retval EFI_SUCCESS            The operation is successfully started.\r
600 \r
601 **/\r
602 STATIC\r
603 EFI_STATUS\r
604 Mtftp4Start (\r
605   IN EFI_MTFTP4_PROTOCOL    *This,\r
606   IN EFI_MTFTP4_TOKEN       *Token,\r
607   IN UINT16                 Operation\r
608   )\r
609 {\r
610   MTFTP4_PROTOCOL           *Instance;\r
611   EFI_MTFTP4_OVERRIDE_DATA  *Override;\r
612   EFI_MTFTP4_CONFIG_DATA    *Config;\r
613   EFI_TPL                   OldTpl;\r
614   EFI_STATUS                Status;\r
615 \r
616   //\r
617   // Validate the parameters\r
618   //\r
619   if ((This == NULL) || (Token == NULL) || (Token->Filename == NULL) ||\r
620       ((Token->OptionCount != 0) && (Token->OptionList == NULL))) {\r
621     return EFI_INVALID_PARAMETER;\r
622   }\r
623 \r
624   //\r
625   // User must provide at least one method to collect the data for download.\r
626   //\r
627   if (((Operation == EFI_MTFTP4_OPCODE_RRQ) || (Operation == EFI_MTFTP4_OPCODE_DIR)) &&\r
628       ((Token->Buffer == NULL) && (Token->CheckPacket == NULL))) {\r
629     return EFI_INVALID_PARAMETER;\r
630   }\r
631 \r
632   //\r
633   // User must provide at least one method to provide the data for upload.\r
634   //\r
635   if ((Operation == EFI_MTFTP4_OPCODE_WRQ) &&\r
636      ((Token->Buffer == NULL) && (Token->PacketNeeded == NULL))) {\r
637     return EFI_INVALID_PARAMETER;\r
638   }\r
639 \r
640   Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
641 \r
642   Status = EFI_SUCCESS;\r
643   OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
644 \r
645   if (Instance->State != MTFTP4_STATE_CONFIGED) {\r
646     Status = EFI_NOT_STARTED;\r
647   }\r
648 \r
649   if (Instance->Operation != 0) {\r
650     Status = EFI_ACCESS_DENIED;\r
651   }\r
652 \r
653   if (EFI_ERROR (Status)) {\r
654     NET_RESTORE_TPL (OldTpl);\r
655     return Status;\r
656   }\r
657 \r
658   //\r
659   // Set the Operation now to prevent the application start other\r
660   // operations.\r
661   //\r
662   Instance->Operation = Operation;\r
663   Override            = Token->OverrideData;\r
664 \r
665   if ((Override != NULL) && !Mtftp4OverrideValid (Instance, Override)) {\r
666     Status = EFI_INVALID_PARAMETER;\r
667     goto ON_ERROR;\r
668   }\r
669 \r
670   if (Token->OptionCount != 0) {\r
671     Status = Mtftp4ParseOption (\r
672                Token->OptionList,\r
673                Token->OptionCount,\r
674                TRUE,\r
675                &Instance->RequestOption\r
676                );\r
677 \r
678     if (EFI_ERROR (Status)) {\r
679       goto ON_ERROR;\r
680     }\r
681   }\r
682 \r
683   //\r
684   // Set the operation parameters from the configuration or override data.\r
685   //\r
686   Config                  = &Instance->Config;\r
687   Instance->Token         = Token;\r
688   Instance->BlkSize       = MTFTP4_DEFAULT_BLKSIZE;\r
689 \r
690   NetCopyMem (&Instance->ServerIp, &Config->ServerIp, sizeof (IP4_ADDR));\r
691   Instance->ServerIp      = NTOHL (Instance->ServerIp);\r
692 \r
693   Instance->ListeningPort = Config->InitialServerPort;\r
694   Instance->ConnectedPort = 0;\r
695 \r
696   NetCopyMem (&Instance->Gateway, &Config->GatewayIp, sizeof (IP4_ADDR));\r
697   Instance->Gateway       = NTOHL (Instance->Gateway);\r
698 \r
699   Instance->MaxRetry      = Config->TryCount;\r
700   Instance->Timeout       = Config->TimeoutValue;\r
701   Instance->Master        = TRUE;\r
702 \r
703   if (Override != NULL) {\r
704     NetCopyMem (&Instance->ServerIp, &Override->ServerIp, sizeof (IP4_ADDR));\r
705     NetCopyMem (&Instance->Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));\r
706 \r
707     Instance->ServerIp      = NTOHL (Instance->ServerIp);\r
708     Instance->Gateway       = NTOHL (Instance->Gateway);\r
709 \r
710     Instance->ListeningPort = Override->ServerPort;\r
711     Instance->MaxRetry      = Override->TryCount;\r
712     Instance->Timeout       = Override->TimeoutValue;\r
713   }\r
714 \r
715   if (Instance->ListeningPort == 0) {\r
716     Instance->ListeningPort = MTFTP4_DEFAULT_SERVER_PORT;\r
717   }\r
718 \r
719   if (Instance->MaxRetry == 0) {\r
720     Instance->MaxRetry = MTFTP4_DEFAULT_RETRY;\r
721   }\r
722 \r
723   if (Instance->Timeout == 0) {\r
724     Instance->Timeout = MTFTP4_DEFAULT_TIMEOUT;\r
725   }\r
726 \r
727   //\r
728   // Config the unicast UDP child to send initial request\r
729   //\r
730   Status = Mtftp4ConfigUnicastPort (Instance->UnicastPort, Instance);\r
731 \r
732   if (EFI_ERROR (Status)) {\r
733     goto ON_ERROR;\r
734   }\r
735 \r
736   //\r
737   // Build and send an initial requests\r
738   //\r
739   if (Operation == EFI_MTFTP4_OPCODE_WRQ) {\r
740     Status = Mtftp4WrqStart (Instance, Operation);\r
741   } else {\r
742     Status = Mtftp4RrqStart (Instance, Operation);\r
743   }\r
744 \r
745   NET_RESTORE_TPL (OldTpl);\r
746 \r
747   if (EFI_ERROR (Status)) {\r
748     goto ON_ERROR;\r
749   }\r
750   //\r
751   // Return immediately for asynchronous operation or poll the\r
752   // instance for synchronous operation.\r
753   //\r
754   Token->Status = EFI_NOT_READY;\r
755 \r
756   if (Token->Event != NULL) {\r
757     return EFI_SUCCESS;\r
758   }\r
759 \r
760   while (Token->Status == EFI_NOT_READY) {\r
761     This->Poll (This);\r
762   }\r
763 \r
764   return Token->Status;\r
765 \r
766 ON_ERROR:\r
767   Mtftp4CleanOperation (Instance, Status);\r
768   NET_RESTORE_TPL (OldTpl);\r
769 \r
770   return Status;\r
771 }\r
772 \r
773 \r
774 /**\r
775   Read a file from the server.\r
776 \r
777   @param  This                   The Mtftp protocol instance.\r
778   @param  Token                  The user's request wrap token.\r
779 \r
780   @retval EFI_SUCCESS            The ReadFile has finished, the file has been\r
781                                  downloaded if it is synchronous operation,\r
782                                  otherwise it has been  initated.\r
783   @retval Others                 Some error happened.\r
784 \r
785 **/\r
786 STATIC\r
787 EFI_STATUS\r
788 EFIAPI\r
789 EfiMtftp4ReadFile (\r
790   IN EFI_MTFTP4_PROTOCOL    *This,\r
791   IN EFI_MTFTP4_TOKEN       *Token\r
792   )\r
793 {\r
794   return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_RRQ);\r
795 }\r
796 \r
797 \r
798 /**\r
799   Upload a file to the server.\r
800 \r
801   @param  This                   The MTFTP protocol session\r
802   @param  Token                  The user's request wrap token.\r
803 \r
804   @retval EFI_SUCCESS            The WriteFile has finished, the file has been\r
805                                  uploaded if it is synchronous operation, otherwise\r
806                                  it has been  initated.\r
807   @retval Others                 Some error happened.\r
808 \r
809 **/\r
810 STATIC\r
811 EFI_STATUS\r
812 EFIAPI\r
813 EfiMtftp4WriteFile (\r
814   IN EFI_MTFTP4_PROTOCOL    *This,\r
815   IN EFI_MTFTP4_TOKEN       *Token\r
816   )\r
817 {\r
818   return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_WRQ);\r
819 }\r
820 \r
821 \r
822 /**\r
823   Read a directory from the server. The only difference\r
824   between ReadFile and ReadDirectory is the opcode used.\r
825 \r
826   @param  This                   The MTFTP protocol session\r
827   @param  Token                  The user's request wrap token.\r
828 \r
829   @retval EFI_SUCCESS            The ReadDirectory has finished, the directory has\r
830                                  been  downloaded as a file if it is synchronous\r
831                                  operation,  otherwise it has been initated.\r
832   @retval Others                 Some error happened.\r
833 \r
834 **/\r
835 STATIC\r
836 EFI_STATUS\r
837 EFIAPI\r
838 EfiMtftp4ReadDirectory (\r
839   IN EFI_MTFTP4_PROTOCOL        *This,\r
840   IN EFI_MTFTP4_TOKEN           *Token\r
841   )\r
842 {\r
843   return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_DIR);\r
844 }\r
845 \r
846 \r
847 /**\r
848   Poll the network stack to accelerate the packet process.\r
849 \r
850   @param  This                   The MTFTP protocol instance.\r
851 \r
852   @retval EFI_INVALID_PARAMETER  This is NULL.\r
853   @retval EFI_NOT_STARTED        The MTFTP session hasn't been configured.\r
854   @retval EFI_DEVICE_ERROR       The MTFTP session has been destoried.\r
855 \r
856 **/\r
857 STATIC\r
858 EFI_STATUS\r
859 EFIAPI\r
860 EfiMtftp4Poll (\r
861   IN EFI_MTFTP4_PROTOCOL    *This\r
862   )\r
863 {\r
864   MTFTP4_PROTOCOL           *Instance;\r
865   EFI_UDP4_PROTOCOL         *Udp;\r
866 \r
867   if (This == NULL) {\r
868     return EFI_INVALID_PARAMETER;\r
869   }\r
870 \r
871   Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
872 \r
873   if (Instance->State == MTFTP4_STATE_UNCONFIGED) {\r
874     return EFI_NOT_STARTED;\r
875   } else if (Instance->State == MTFTP4_STATE_DESTORY) {\r
876     return EFI_DEVICE_ERROR;\r
877   }\r
878 \r
879   Udp = Instance->UnicastPort->Udp;\r
880   return Udp->Poll (Udp);\r
881 }\r
882 \r
883 EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate = {\r
884   EfiMtftp4GetModeData,\r
885   EfiMtftp4Configure,\r
886   EfiMtftp4GetInfo,\r
887   EfiMtftp4ParseOptions,\r
888   EfiMtftp4ReadFile,\r
889   EfiMtftp4WriteFile,\r
890   EfiMtftp4ReadDirectory,\r
891   EfiMtftp4Poll\r
892 };\r