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