a0ec216e072c635ac16fc7662826d78388cccac7
[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 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 = gBS->RaiseTPL (TPL_CALLBACK);\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   gBS->RestoreTPL (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   LIST_ENTRY                *Entry;\r
91   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     RemoveEntryList (Entry);\r
126     gBS->FreePool (Block);\r
127   }\r
128 \r
129   ZeroMem (&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 = gBS->RaiseTPL (TPL_CALLBACK);\r
187 \r
188     Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
189     ZeroMem (&Instance->Config, sizeof (EFI_MTFTP4_CONFIG_DATA));\r
190     Instance->State = MTFTP4_STATE_UNCONFIGED;\r
191 \r
192     gBS->RestoreTPL (OldTpl);\r
193 \r
194   } else {\r
195     //\r
196     // Configure the parameters for new operation.\r
197     //\r
198     CopyMem (&Ip, &ConfigData->StationIp, sizeof (IP4_ADDR));\r
199     CopyMem (&Netmask, &ConfigData->SubnetMask, sizeof (IP4_ADDR));\r
200     CopyMem (&Gateway, &ConfigData->GatewayIp, sizeof (IP4_ADDR));\r
201     CopyMem (&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 = gBS->RaiseTPL (TPL_CALLBACK);\r
225 \r
226     if ((Instance->State == MTFTP4_STATE_CONFIGED) && (Instance->Operation != 0)) {\r
227       gBS->RestoreTPL (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     gBS->RestoreTPL (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_PROTOCOL           *Instance;\r
264   MTFTP4_GETINFO_STATE      *State;\r
265   EFI_STATUS                Status;\r
266   UINT16                    OpCode;\r
267 \r
268   Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
269   State    = &Instance->GetInfoState;\r
270   OpCode   = NTOHS (Packet->OpCode);\r
271 \r
272   //\r
273   // Set the GetInfo's return status according to the OpCode.\r
274   //\r
275   switch (OpCode) {\r
276   case EFI_MTFTP4_OPCODE_ERROR:\r
277     State->Status = EFI_TFTP_ERROR;\r
278     break;\r
279 \r
280   case EFI_MTFTP4_OPCODE_OACK:\r
281     State->Status = EFI_SUCCESS;\r
282     break;\r
283 \r
284   default:\r
285     State->Status = EFI_PROTOCOL_ERROR;\r
286   }\r
287 \r
288   //\r
289   // Allocate buffer then copy the packet over. Use gBS->AllocatePool\r
290   // in case AllocatePool will implements something tricky.\r
291   //\r
292   Status = gBS->AllocatePool (EfiBootServicesData, PacketLen, (VOID **) State->Packet);\r
293 \r
294   if (EFI_ERROR (Status)) {\r
295     State->Status = EFI_OUT_OF_RESOURCES;\r
296     return EFI_ABORTED;\r
297   }\r
298 \r
299   *(State->PacketLen) = PacketLen;\r
300   CopyMem (*(State->Packet), Packet, PacketLen);\r
301 \r
302   return EFI_ABORTED;\r
303 }\r
304 \r
305 \r
306 /**\r
307   Get the information of the download from the server. It is implemented\r
308   with EfiMtftp4ReadFile: build a token, then pass it to EfiMtftp4ReadFile.\r
309   In its check packet callback abort the opertions.\r
310 \r
311   @param  This                   The MTFTP protocol instance\r
312   @param  OverrideData           The MTFTP override data\r
313   @param  Filename               The file to get information\r
314   @param  ModeStr                The mode to use\r
315   @param  OptionCount            The number of options to append\r
316   @param  OptionList             The options to append\r
317   @param  PacketLength           The variable to receive the packet length\r
318   @param  Packet                 The variable to receive the packet.\r
319 \r
320   @retval EFI_INVALID_PARAMETER  The parameter is invaid\r
321   @retval EFI_SUCCESS            The information is got\r
322   @retval Others                 Failed to get the information.\r
323 \r
324 **/\r
325 STATIC\r
326 EFI_STATUS\r
327 EFIAPI\r
328 EfiMtftp4GetInfo (\r
329   IN EFI_MTFTP4_PROTOCOL      *This,\r
330   IN EFI_MTFTP4_OVERRIDE_DATA *OverrideData,        OPTIONAL\r
331   IN UINT8                    *Filename,\r
332   IN UINT8                    *ModeStr,             OPTIONAL\r
333   IN UINT8                    OptionCount,\r
334   IN EFI_MTFTP4_OPTION        *OptionList,\r
335   OUT UINT32                  *PacketLength,\r
336   OUT EFI_MTFTP4_PACKET       **Packet OPTIONAL\r
337   )\r
338 {\r
339   EFI_MTFTP4_TOKEN          Token;\r
340   MTFTP4_PROTOCOL           *Instance;\r
341   MTFTP4_GETINFO_STATE      *State;\r
342   EFI_STATUS                Status;\r
343 \r
344   if ((This == NULL) || (Filename == NULL) || (PacketLength == NULL) ||\r
345       (OptionCount && (OptionList == NULL))) {\r
346     return EFI_INVALID_PARAMETER;\r
347   }\r
348 \r
349   if (Packet != NULL) {\r
350     *Packet = NULL;\r
351   }\r
352 \r
353   *PacketLength         = 0;\r
354   Instance              = MTFTP4_PROTOCOL_FROM_THIS (This);\r
355   State                 = &Instance->GetInfoState;\r
356   State->Packet          = Packet;\r
357   State->PacketLen       = PacketLength;\r
358   State->Status          = EFI_SUCCESS;\r
359 \r
360   //\r
361   // Fill in the Token to issue an synchronous ReadFile operation\r
362   //\r
363   Token.Status          = EFI_SUCCESS;\r
364   Token.Event           = NULL;\r
365   Token.OverrideData    = OverrideData;\r
366   Token.Filename        = Filename;\r
367   Token.ModeStr         = ModeStr;\r
368   Token.OptionCount     = OptionCount;\r
369   Token.OptionList      = OptionList;\r
370   Token.BufferSize      = 0;\r
371   Token.Buffer          = NULL;\r
372   Token.CheckPacket     = Mtftp4GetInfoCheckPacket;\r
373   Token.TimeoutCallback = NULL;\r
374   Token.PacketNeeded    = NULL;\r
375 \r
376   Status                = EfiMtftp4ReadFile (This, &Token);\r
377 \r
378   if (EFI_ABORTED == Status) {\r
379     return State->Status;\r
380   }\r
381 \r
382   return Status;\r
383 }\r
384 \r
385 \r
386 /**\r
387   Parse the packet into an array of options. The OptionList is allocated\r
388   by this function, and caller should free it when used.\r
389 \r
390   @param  This                   The MTFTP protocol instance\r
391   @param  PacketLen              The length of the packet\r
392   @param  Packet                 The packet to parse\r
393   @param  OptionCount            The size of the OptionList array allocated.\r
394   @param  OptionList             The allocated option array to save the option\r
395                                  addresses.\r
396 \r
397   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
398   @retval EFI_NOT_FOUND          There is no valid option in the packet\r
399   @retval EFI_SUCCESS            The packet is parsed.\r
400 \r
401 **/\r
402 STATIC\r
403 EFI_STATUS\r
404 EFIAPI\r
405 EfiMtftp4ParseOptions (\r
406   IN EFI_MTFTP4_PROTOCOL    *This,\r
407   IN UINT32                 PacketLen,\r
408   IN EFI_MTFTP4_PACKET      *Packet,\r
409   IN OUT UINT32             *OptionCount,\r
410   OUT EFI_MTFTP4_OPTION     **OptionList          OPTIONAL\r
411   )\r
412 {\r
413   EFI_STATUS                Status;\r
414 \r
415   if ((This == NULL) || (PacketLen < MTFTP4_OPCODE_LEN) ||\r
416       (Packet == NULL) || (OptionCount == NULL)) {\r
417 \r
418     return EFI_INVALID_PARAMETER;\r
419   }\r
420 \r
421   Status = Mtftp4ExtractOptions (Packet, PacketLen, OptionCount, OptionList);\r
422 \r
423   if (EFI_ERROR (Status)) {\r
424     return Status;\r
425   }\r
426 \r
427   if (*OptionCount == 0) {\r
428     return EFI_NOT_FOUND;\r
429   }\r
430 \r
431   return EFI_SUCCESS;\r
432 }\r
433 \r
434 \r
435 /**\r
436   Check whether the override data is valid. It will first\r
437   validate whether the server is a valid unicast. If a gateway\r
438   is provided in the Override, it also check that it is a\r
439   unicast on the connected network.\r
440 \r
441   @param  Instance               The MTFTP instance\r
442   @param  Override               The override data to validate.\r
443 \r
444   @return TRUE if the override data is valid, otherwise FALSE.\r
445 \r
446 **/\r
447 STATIC\r
448 BOOLEAN\r
449 Mtftp4OverrideValid (\r
450   IN MTFTP4_PROTOCOL          *Instance,\r
451   IN EFI_MTFTP4_OVERRIDE_DATA *Override\r
452   )\r
453 {\r
454   EFI_MTFTP4_CONFIG_DATA    *Config;\r
455   IP4_ADDR                  Ip;\r
456   IP4_ADDR                  Netmask;\r
457   IP4_ADDR                  Gateway;\r
458 \r
459   CopyMem (&Ip, &Override->ServerIp, sizeof (IP4_ADDR));\r
460   if (!Ip4IsUnicast (NTOHL (Ip), 0)) {\r
461     return FALSE;\r
462   }\r
463 \r
464   Config = &Instance->Config;\r
465 \r
466   CopyMem (&Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));\r
467   Gateway = NTOHL (Gateway);\r
468 \r
469   if (!Config->UseDefaultSetting && (Gateway != 0)) {\r
470     CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));\r
471     CopyMem (&Ip, &Config->StationIp, sizeof (IP4_ADDR));\r
472 \r
473     Netmask = NTOHL (Netmask);\r
474     Ip      = NTOHL (Ip);\r
475 \r
476     if (!Ip4IsUnicast (Gateway, Netmask) || !IP4_NET_EQUAL (Gateway, Ip, Netmask)) {\r
477       return FALSE;\r
478     }\r
479   }\r
480 \r
481   return TRUE;\r
482 }\r
483 \r
484 \r
485 /**\r
486   Poll the UDP to get the IP4 default address, which may be retrieved\r
487   by DHCP. The default time out value is 5 seconds. If IP has retrieved\r
488   the default address, the UDP is reconfigured.\r
489 \r
490   @param  Instance               The Mtftp instance\r
491   @param  UdpPort                The UDP port to poll\r
492   @param  UdpCfgData             The UDP configure data to reconfigure the UDP\r
493                                  port.\r
494 \r
495   @return TRUE if the default address is retrieved and UDP is reconfigured.\r
496   @return Otherwise FALSE.\r
497 \r
498 **/\r
499 BOOLEAN\r
500 Mtftp4GetMapping (\r
501   IN MTFTP4_PROTOCOL        *Instance,\r
502   IN UDP_IO_PORT            *UdpPort,\r
503   IN EFI_UDP4_CONFIG_DATA   *UdpCfgData\r
504   )\r
505 {\r
506   MTFTP4_SERVICE            *Service;\r
507   EFI_IP4_MODE_DATA         Ip4Mode;\r
508   EFI_UDP4_PROTOCOL         *Udp;\r
509   EFI_STATUS                Status;\r
510 \r
511   ASSERT (Instance->Config.UseDefaultSetting);\r
512 \r
513   Service = Instance->Service;\r
514   Udp     = UdpPort->Udp;\r
515 \r
516   Status = gBS->SetTimer (\r
517                   Service->TimerToGetMap,\r
518                   TimerRelative,\r
519                   MTFTP4_TIME_TO_GETMAP * TICKS_PER_SECOND\r
520                   );\r
521   if (EFI_ERROR (Status)) {\r
522     return FALSE;\r
523   }\r
524 \r
525   while (!EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {\r
526     Udp->Poll (Udp);\r
527 \r
528     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&\r
529         Ip4Mode.IsConfigured) {\r
530 \r
531       Udp->Configure (Udp, NULL);\r
532       return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);\r
533     }\r
534   }\r
535 \r
536   return FALSE;\r
537 }\r
538 \r
539 \r
540 /**\r
541   Configure the UDP port for unicast receiving.\r
542 \r
543   @param  UdpIo                  The UDP port\r
544   @param  Instance               The MTFTP session\r
545 \r
546   @retval EFI_SUCCESS            The UDP port is successfully configured for the\r
547                                  session to unicast receive.\r
548 \r
549 **/\r
550 STATIC\r
551 EFI_STATUS\r
552 Mtftp4ConfigUnicastPort (\r
553   IN UDP_IO_PORT            *UdpIo,\r
554   IN MTFTP4_PROTOCOL        *Instance\r
555   )\r
556 {\r
557   EFI_MTFTP4_CONFIG_DATA    *Config;\r
558   EFI_UDP4_CONFIG_DATA      UdpConfig;\r
559   EFI_STATUS                Status;\r
560   IP4_ADDR                  Ip;\r
561 \r
562   Config = &Instance->Config;\r
563 \r
564   UdpConfig.AcceptBroadcast    = FALSE;\r
565   UdpConfig.AcceptPromiscuous  = FALSE;\r
566   UdpConfig.AcceptAnyPort      = FALSE;\r
567   UdpConfig.AllowDuplicatePort = FALSE;\r
568   UdpConfig.TypeOfService      = 0;\r
569   UdpConfig.TimeToLive         = 64;\r
570   UdpConfig.DoNotFragment      = FALSE;\r
571   UdpConfig.ReceiveTimeout     = 0;\r
572   UdpConfig.TransmitTimeout    = 0;\r
573   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;\r
574   UdpConfig.StationAddress     = Config->StationIp;\r
575   UdpConfig.SubnetMask         = Config->SubnetMask;\r
576   UdpConfig.StationPort        = 0;\r
577   UdpConfig.RemotePort         = 0;\r
578 \r
579   Ip = HTONL (Instance->ServerIp);\r
580   CopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
581 \r
582   Status = UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfig);\r
583 \r
584   if ((Status == EFI_NO_MAPPING) && Mtftp4GetMapping (Instance, UdpIo, &UdpConfig)) {\r
585     return EFI_SUCCESS;\r
586   }\r
587 \r
588   if (!Config->UseDefaultSetting && !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) {\r
589     //\r
590     // The station IP address is manually configured and the Gateway IP is not 0.\r
591     // Add the default route for this UDP instance.\r
592     //\r
593     Status = UdpIo->Udp->Routes (UdpIo->Udp, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &Config->GatewayIp);\r
594     if (EFI_ERROR (Status)) {\r
595       UdpIo->Udp->Configure (UdpIo->Udp, NULL);\r
596     }\r
597   }\r
598   return Status;\r
599 }\r
600 \r
601 \r
602 /**\r
603   Start the MTFTP session to do the operation, such as read file,\r
604   write file, and read directory.\r
605 \r
606   @param  This                   The MTFTP session\r
607   @param  Token                  The token than encapsues the user's request.\r
608   @param  Operation              The operation to do\r
609 \r
610   @retval EFI_INVALID_PARAMETER  Some of the parameters are invalid.\r
611   @retval EFI_NOT_STARTED        The MTFTP session hasn't been configured.\r
612   @retval EFI_ALREADY_STARTED    There is pending operation for the session.\r
613   @retval EFI_SUCCESS            The operation is successfully started.\r
614 \r
615 **/\r
616 STATIC\r
617 EFI_STATUS\r
618 Mtftp4Start (\r
619   IN EFI_MTFTP4_PROTOCOL    *This,\r
620   IN EFI_MTFTP4_TOKEN       *Token,\r
621   IN UINT16                 Operation\r
622   )\r
623 {\r
624   MTFTP4_PROTOCOL           *Instance;\r
625   EFI_MTFTP4_OVERRIDE_DATA  *Override;\r
626   EFI_MTFTP4_CONFIG_DATA    *Config;\r
627   EFI_TPL                   OldTpl;\r
628   EFI_STATUS                Status;\r
629 \r
630   //\r
631   // Validate the parameters\r
632   //\r
633   if ((This == NULL) || (Token == NULL) || (Token->Filename == NULL) ||\r
634       ((Token->OptionCount != 0) && (Token->OptionList == NULL))) {\r
635     return EFI_INVALID_PARAMETER;\r
636   }\r
637 \r
638   //\r
639   // User must provide at least one method to collect the data for download.\r
640   //\r
641   if (((Operation == EFI_MTFTP4_OPCODE_RRQ) || (Operation == EFI_MTFTP4_OPCODE_DIR)) &&\r
642       ((Token->Buffer == NULL) && (Token->CheckPacket == NULL))) {\r
643     return EFI_INVALID_PARAMETER;\r
644   }\r
645 \r
646   //\r
647   // User must provide at least one method to provide the data for upload.\r
648   //\r
649   if ((Operation == EFI_MTFTP4_OPCODE_WRQ) &&\r
650      ((Token->Buffer == NULL) && (Token->PacketNeeded == NULL))) {\r
651     return EFI_INVALID_PARAMETER;\r
652   }\r
653 \r
654   Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
655 \r
656   Status = EFI_SUCCESS;\r
657   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
658 \r
659   if (Instance->State != MTFTP4_STATE_CONFIGED) {\r
660     Status = EFI_NOT_STARTED;\r
661   }\r
662 \r
663   if (Instance->Operation != 0) {\r
664     Status = EFI_ACCESS_DENIED;\r
665   }\r
666 \r
667   if (EFI_ERROR (Status)) {\r
668     gBS->RestoreTPL (OldTpl);\r
669     return Status;\r
670   }\r
671 \r
672   //\r
673   // Set the Operation now to prevent the application start other\r
674   // operations.\r
675   //\r
676   Instance->Operation = Operation;\r
677   Override            = Token->OverrideData;\r
678 \r
679   if ((Override != NULL) && !Mtftp4OverrideValid (Instance, Override)) {\r
680     Status = EFI_INVALID_PARAMETER;\r
681     goto ON_ERROR;\r
682   }\r
683 \r
684   if (Token->OptionCount != 0) {\r
685     Status = Mtftp4ParseOption (\r
686                Token->OptionList,\r
687                Token->OptionCount,\r
688                TRUE,\r
689                &Instance->RequestOption\r
690                );\r
691 \r
692     if (EFI_ERROR (Status)) {\r
693       goto ON_ERROR;\r
694     }\r
695   }\r
696 \r
697   //\r
698   // Set the operation parameters from the configuration or override data.\r
699   //\r
700   Config                  = &Instance->Config;\r
701   Instance->Token         = Token;\r
702   Instance->BlkSize       = MTFTP4_DEFAULT_BLKSIZE;\r
703 \r
704   CopyMem (&Instance->ServerIp, &Config->ServerIp, sizeof (IP4_ADDR));\r
705   Instance->ServerIp      = NTOHL (Instance->ServerIp);\r
706 \r
707   Instance->ListeningPort = Config->InitialServerPort;\r
708   Instance->ConnectedPort = 0;\r
709 \r
710   CopyMem (&Instance->Gateway, &Config->GatewayIp, sizeof (IP4_ADDR));\r
711   Instance->Gateway       = NTOHL (Instance->Gateway);\r
712 \r
713   Instance->MaxRetry      = Config->TryCount;\r
714   Instance->Timeout       = Config->TimeoutValue;\r
715   Instance->Master        = TRUE;\r
716 \r
717   if (Override != NULL) {\r
718     CopyMem (&Instance->ServerIp, &Override->ServerIp, sizeof (IP4_ADDR));\r
719     CopyMem (&Instance->Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));\r
720 \r
721     Instance->ServerIp      = NTOHL (Instance->ServerIp);\r
722     Instance->Gateway       = NTOHL (Instance->Gateway);\r
723 \r
724     Instance->ListeningPort = Override->ServerPort;\r
725     Instance->MaxRetry      = Override->TryCount;\r
726     Instance->Timeout       = Override->TimeoutValue;\r
727   }\r
728 \r
729   if (Instance->ListeningPort == 0) {\r
730     Instance->ListeningPort = MTFTP4_DEFAULT_SERVER_PORT;\r
731   }\r
732 \r
733   if (Instance->MaxRetry == 0) {\r
734     Instance->MaxRetry = MTFTP4_DEFAULT_RETRY;\r
735   }\r
736 \r
737   if (Instance->Timeout == 0) {\r
738     Instance->Timeout = MTFTP4_DEFAULT_TIMEOUT;\r
739   }\r
740 \r
741   //\r
742   // Config the unicast UDP child to send initial request\r
743   //\r
744   Status = Mtftp4ConfigUnicastPort (Instance->UnicastPort, Instance);\r
745 \r
746   if (EFI_ERROR (Status)) {\r
747     goto ON_ERROR;\r
748   }\r
749 \r
750   //\r
751   // Set initial status.\r
752   //\r
753   Token->Status = EFI_NOT_READY;\r
754 \r
755   //\r
756   // Build and send an initial requests\r
757   //\r
758   if (Operation == EFI_MTFTP4_OPCODE_WRQ) {\r
759     Status = Mtftp4WrqStart (Instance, Operation);\r
760   } else {\r
761     Status = Mtftp4RrqStart (Instance, Operation);\r
762   }\r
763 \r
764   gBS->RestoreTPL (OldTpl);\r
765 \r
766   if (EFI_ERROR (Status)) {\r
767     goto ON_ERROR;\r
768   }\r
769 \r
770   if (Token->Event != NULL) {\r
771     return EFI_SUCCESS;\r
772   }\r
773 \r
774   //\r
775   // Return immediately for asynchronous operation or poll the\r
776   // instance for synchronous operation.\r
777   //\r
778   while (Token->Status == EFI_NOT_READY) {\r
779     This->Poll (This);\r
780   }\r
781 \r
782   return Token->Status;\r
783 \r
784 ON_ERROR:\r
785   Mtftp4CleanOperation (Instance, Status);\r
786   gBS->RestoreTPL (OldTpl);\r
787 \r
788   return Status;\r
789 }\r
790 \r
791 \r
792 /**\r
793   Read a file from the server.\r
794 \r
795   @param  This                   The Mtftp protocol instance.\r
796   @param  Token                  The user's request wrap token.\r
797 \r
798   @retval EFI_SUCCESS            The ReadFile has finished, the file has been\r
799                                  downloaded if it is synchronous operation,\r
800                                  otherwise it has been  initated.\r
801   @retval Others                 Some error happened.\r
802 \r
803 **/\r
804 STATIC\r
805 EFI_STATUS\r
806 EFIAPI\r
807 EfiMtftp4ReadFile (\r
808   IN EFI_MTFTP4_PROTOCOL    *This,\r
809   IN EFI_MTFTP4_TOKEN       *Token\r
810   )\r
811 {\r
812   return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_RRQ);\r
813 }\r
814 \r
815 \r
816 /**\r
817   Upload a file to the server.\r
818 \r
819   @param  This                   The MTFTP protocol session\r
820   @param  Token                  The user's request wrap token.\r
821 \r
822   @retval EFI_SUCCESS            The WriteFile has finished, the file has been\r
823                                  uploaded if it is synchronous operation, otherwise\r
824                                  it has been  initated.\r
825   @retval Others                 Some error happened.\r
826 \r
827 **/\r
828 STATIC\r
829 EFI_STATUS\r
830 EFIAPI\r
831 EfiMtftp4WriteFile (\r
832   IN EFI_MTFTP4_PROTOCOL    *This,\r
833   IN EFI_MTFTP4_TOKEN       *Token\r
834   )\r
835 {\r
836   return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_WRQ);\r
837 }\r
838 \r
839 \r
840 /**\r
841   Read a directory from the server. The only difference\r
842   between ReadFile and ReadDirectory is the opcode used.\r
843 \r
844   @param  This                   The MTFTP protocol session\r
845   @param  Token                  The user's request wrap token.\r
846 \r
847   @retval EFI_SUCCESS            The ReadDirectory has finished, the directory has\r
848                                  been  downloaded as a file if it is synchronous\r
849                                  operation,  otherwise it has been initated.\r
850   @retval Others                 Some error happened.\r
851 \r
852 **/\r
853 STATIC\r
854 EFI_STATUS\r
855 EFIAPI\r
856 EfiMtftp4ReadDirectory (\r
857   IN EFI_MTFTP4_PROTOCOL        *This,\r
858   IN EFI_MTFTP4_TOKEN           *Token\r
859   )\r
860 {\r
861   return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_DIR);\r
862 }\r
863 \r
864 \r
865 /**\r
866   Poll the network stack to accelerate the packet process.\r
867 \r
868   @param  This                   The MTFTP protocol instance.\r
869 \r
870   @retval EFI_INVALID_PARAMETER  This is NULL.\r
871   @retval EFI_NOT_STARTED        The MTFTP session hasn't been configured.\r
872   @retval EFI_DEVICE_ERROR       The MTFTP session has been destoried.\r
873 \r
874 **/\r
875 STATIC\r
876 EFI_STATUS\r
877 EFIAPI\r
878 EfiMtftp4Poll (\r
879   IN EFI_MTFTP4_PROTOCOL    *This\r
880   )\r
881 {\r
882   MTFTP4_PROTOCOL           *Instance;\r
883   EFI_UDP4_PROTOCOL         *Udp;\r
884 \r
885   if (This == NULL) {\r
886     return EFI_INVALID_PARAMETER;\r
887   }\r
888 \r
889   Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
890 \r
891   if (Instance->State == MTFTP4_STATE_UNCONFIGED) {\r
892     return EFI_NOT_STARTED;\r
893   } else if (Instance->State == MTFTP4_STATE_DESTORY) {\r
894     return EFI_DEVICE_ERROR;\r
895   }\r
896 \r
897   Udp = Instance->UnicastPort->Udp;\r
898   return Udp->Poll (Udp);\r
899 }\r
900 \r
901 EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate = {\r
902   EfiMtftp4GetModeData,\r
903   EfiMtftp4Configure,\r
904   EfiMtftp4GetInfo,\r
905   EfiMtftp4ParseOptions,\r
906   EfiMtftp4ReadFile,\r
907   EfiMtftp4WriteFile,\r
908   EfiMtftp4ReadDirectory,\r
909   EfiMtftp4Poll\r
910 };\r