NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg
[mirror_edk2.git] / NetworkPkg / Ip4Dxe / Ip4Impl.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
4 SPDX-License-Identifier: BSD-2-Clause-Patent\r
5 \r
6 **/\r
7 \r
8 #include "Ip4Impl.h"\r
9 \r
10 EFI_IPSEC2_PROTOCOL    *mIpSec = NULL;\r
11 \r
12 /**\r
13   Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.\r
14 \r
15   The GetModeData() function returns the current operational mode data for this\r
16   driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This\r
17   function is used optionally to retrieve the operational mode data of underlying\r
18   networks or drivers.\r
19 \r
20   @param[in]   This          Pointer to the EFI_IP4_PROTOCOL instance.\r
21   @param[out]  Ip4ModeData   Pointer to the EFI IPv4 Protocol mode data structure.\r
22   @param[out]  MnpConfigData Pointer to the managed network configuration data structure.\r
23   @param[out]  SnpModeData   Pointer to the simple network mode data structure.\r
24 \r
25   @retval EFI_SUCCESS           The operation completed successfully.\r
26   @retval EFI_INVALID_PARAMETER This is NULL.\r
27   @retval EFI_OUT_OF_RESOURCES  The required mode data could not be allocated.\r
28 \r
29 **/\r
30 EFI_STATUS\r
31 EFIAPI\r
32 EfiIp4GetModeData (\r
33   IN  CONST EFI_IP4_PROTOCOL                *This,\r
34   OUT       EFI_IP4_MODE_DATA               *Ip4ModeData     OPTIONAL,\r
35   OUT       EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData   OPTIONAL,\r
36   OUT       EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL\r
37   );\r
38 \r
39 /**\r
40   Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.\r
41 \r
42   The Configure() function is used to set, change, or reset the operational\r
43   parameters and filter settings for this EFI IPv4 Protocol instance. Until these\r
44   parameters have been set, no network traffic can be sent or received by this\r
45   instance. Once the parameters have been reset (by calling this function with\r
46   IpConfigData set to NULL), no more traffic can be sent or received until these\r
47   parameters have been set again. Each EFI IPv4 Protocol instance can be started\r
48   and stopped independently of each other by enabling or disabling their receive\r
49   filter settings with the Configure() function.\r
50 \r
51   When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will\r
52   be appended as an alias address into the addresses list in the EFI IPv4 Protocol\r
53   driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL\r
54   to retrieve the default IPv4 address if it is not available yet. Clients could\r
55   frequently call GetModeData() to check the status to ensure that the default IPv4\r
56   address is ready.\r
57 \r
58   If operational parameters are reset or changed, any pending transmit and receive\r
59   requests will be cancelled. Their completion token status will be set to EFI_ABORTED\r
60   and their events will be signaled.\r
61 \r
62   @param[in]  This              Pointer to the EFI_IP4_PROTOCOL instance.\r
63   @param[in]  IpConfigData      Pointer to the EFI IPv4 Protocol configuration data structure.\r
64 \r
65   @retval EFI_SUCCESS           The driver instance was successfully opened.\r
66   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
67                                 RARP, etc.) is not finished yet.\r
68   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
69   @retval EFI_UNSUPPORTED       One or more of the following conditions is TRUE:\r
70                                 A configuration protocol (DHCP, BOOTP, RARP, etc.) could\r
71                                 not be located when clients choose to use the default IPv4\r
72                                 address. This EFI IPv4 Protocol implementation does not\r
73                                 support this requested filter or timeout setting.\r
74   @retval EFI_OUT_OF_RESOURCES  The EFI IPv4 Protocol driver instance data could not be allocated.\r
75   @retval EFI_ALREADY_STARTED   The interface is already open and must be stopped before the\r
76                                 IPv4 address or subnet mask can be changed. The interface must\r
77                                 also be stopped when switching to/from raw packet mode.\r
78   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred. The EFI IPv4\r
79                                 Protocol driver instance is not opened.\r
80 \r
81 **/\r
82 EFI_STATUS\r
83 EFIAPI\r
84 EfiIp4Configure (\r
85   IN EFI_IP4_PROTOCOL       *This,\r
86   IN EFI_IP4_CONFIG_DATA    *IpConfigData       OPTIONAL\r
87   );\r
88 \r
89 /**\r
90   Joins and leaves multicast groups.\r
91 \r
92   The Groups() function is used to join and leave multicast group sessions. Joining\r
93   a group will enable reception of matching multicast packets. Leaving a group will\r
94   disable the multicast packet reception.\r
95 \r
96   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.\r
97 \r
98   @param[in]  This                  Pointer to the EFI_IP4_PROTOCOL instance.\r
99   @param[in]  JoinFlag              Set to TRUE to join the multicast group session and FALSE to leave.\r
100   @param[in]  GroupAddress          Pointer to the IPv4 multicast address.\r
101 \r
102   @retval EFI_SUCCESS           The operation completed successfully.\r
103   @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:\r
104                                 - This is NULL.\r
105                                 - JoinFlag is TRUE and GroupAddress is NULL.\r
106                                 - GroupAddress is not NULL and *GroupAddress is\r
107                                 not a multicast IPv4 address.\r
108   @retval EFI_NOT_STARTED       This instance has not been started.\r
109   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
110                                 RARP, etc.) is not finished yet.\r
111   @retval EFI_OUT_OF_RESOURCES  System resources could not be allocated.\r
112   @retval EFI_UNSUPPORTED       This EFI IPv4 Protocol implementation does not support multicast groups.\r
113   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when\r
114                                 JoinFlag is TRUE).\r
115   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is FALSE).\r
116   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
117 \r
118 **/\r
119 EFI_STATUS\r
120 EFIAPI\r
121 EfiIp4Groups (\r
122   IN EFI_IP4_PROTOCOL       *This,\r
123   IN BOOLEAN                JoinFlag,\r
124   IN EFI_IPv4_ADDRESS       *GroupAddress     OPTIONAL\r
125   );\r
126 \r
127 /**\r
128   Adds and deletes routing table entries.\r
129 \r
130   The Routes() function adds a route to or deletes a route from the routing table.\r
131 \r
132   Routes are determined by comparing the SubnetAddress with the destination IPv4\r
133   address arithmetically AND-ed with the SubnetMask. The gateway address must be\r
134   on the same subnet as the configured station address.\r
135 \r
136   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.\r
137   The default route matches all destination IPv4 addresses that do not match any\r
138   other routes.\r
139 \r
140   A GatewayAddress that is zero is a nonroute. Packets are sent to the destination\r
141   IP address if it can be found in the ARP cache or on the local subnet. One automatic\r
142   nonroute entry will be inserted into the routing table for outgoing packets that\r
143   are addressed to a local subnet (gateway address of 0.0.0.0).\r
144 \r
145   Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI\r
146   IPv4 Protocol instances that use the default IPv4 address will also have copies\r
147   of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these\r
148   copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its\r
149   instances. As a result, client modification to the routing table will be lost.\r
150 \r
151   @param[in]  This                   Pointer to the EFI_IP4_PROTOCOL instance.\r
152   @param[in]  DeleteRoute            Set to TRUE to delete this route from the routing table. Set to\r
153                                      FALSE to add this route to the routing table. SubnetAddress\r
154                                      and SubnetMask are used as the key to each route entry.\r
155   @param[in]  SubnetAddress          The address of the subnet that needs to be routed.\r
156   @param[in]  SubnetMask             The subnet mask of SubnetAddress.\r
157   @param[in]  GatewayAddress         The unicast gateway IPv4 address for this route.\r
158 \r
159   @retval EFI_SUCCESS            The operation completed successfully.\r
160   @retval EFI_NOT_STARTED        The driver instance has not been started.\r
161   @retval EFI_NO_MAPPING         When using the default address, configuration (DHCP, BOOTP,\r
162                                  RARP, etc.) is not finished yet.\r
163   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
164                                  - This is NULL.\r
165                                  - SubnetAddress is NULL.\r
166                                  - SubnetMask is NULL.\r
167                                  - GatewayAddress is NULL.\r
168                                  - *SubnetAddress is not a valid subnet address.\r
169                                  - *SubnetMask is not a valid subnet mask.\r
170                                  - *GatewayAddress is not a valid unicast IPv4 address.\r
171   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.\r
172   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).\r
173   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when\r
174                                   DeleteRoute is FALSE).\r
175 \r
176 **/\r
177 EFI_STATUS\r
178 EFIAPI\r
179 EfiIp4Routes (\r
180   IN EFI_IP4_PROTOCOL       *This,\r
181   IN BOOLEAN                DeleteRoute,\r
182   IN EFI_IPv4_ADDRESS       *SubnetAddress,\r
183   IN EFI_IPv4_ADDRESS       *SubnetMask,\r
184   IN EFI_IPv4_ADDRESS       *GatewayAddress\r
185   );\r
186 \r
187 /**\r
188   Places outgoing data packets into the transmit queue.\r
189 \r
190   The Transmit() function places a sending request in the transmit queue of this\r
191   EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some\r
192   errors occur, the event in the token will be signaled and the status is updated.\r
193 \r
194   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.\r
195   @param[in]  Token Pointer to the transmit token.\r
196 \r
197   @retval  EFI_SUCCESS           The data has been queued for transmission.\r
198   @retval  EFI_NOT_STARTED       This instance has not been started.\r
199   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
200                                  RARP, etc.) is not finished yet.\r
201   @retval  EFI_INVALID_PARAMETER One or more pameters are invalid.\r
202   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.Event\r
203                                  was already in the transmit queue.\r
204   @retval  EFI_NOT_READY         The completion token could not be queued because the transmit\r
205                                  queue is full.\r
206   @retval  EFI_NOT_FOUND         Not route is found to destination address.\r
207   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.\r
208   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too\r
209                                  short to transmit.\r
210   @retval  EFI_BAD_BUFFER_SIZE   The length of the IPv4 header + option length + total data length is\r
211                                  greater than MTU (or greater than the maximum packet size if\r
212                                  Token.Packet.TxData.OverrideData.\r
213                                  DoNotFragment is TRUE.)\r
214 \r
215 **/\r
216 EFI_STATUS\r
217 EFIAPI\r
218 EfiIp4Transmit (\r
219   IN EFI_IP4_PROTOCOL         *This,\r
220   IN EFI_IP4_COMPLETION_TOKEN *Token\r
221   );\r
222 \r
223 /**\r
224   Places a receiving request into the receiving queue.\r
225 \r
226   The Receive() function places a completion token into the receive packet queue.\r
227   This function is always asynchronous.\r
228 \r
229   The Token.Event field in the completion token must be filled in by the caller\r
230   and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol\r
231   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event\r
232   is signaled.\r
233 \r
234   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.\r
235   @param[in]  Token Pointer to a token that is associated with the receive data descriptor.\r
236 \r
237   @retval EFI_SUCCESS           The receive completion token was cached.\r
238   @retval EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.\r
239   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP, RARP, etc.)\r
240                                 is not finished yet.\r
241   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
242                                 - This is NULL.\r
243                                 - Token is NULL.\r
244                                 - Token.Event is NULL.\r
245   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system\r
246                                 resources (usually memory).\r
247   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
248                                 The EFI IPv4 Protocol instance has been reset to startup defaults.\r
249                                 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already\r
250                                 in the receive queue.\r
251   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.\r
252   @retval EFI_ICMP_ERROR        An ICMP error packet was received.\r
253 \r
254 **/\r
255 EFI_STATUS\r
256 EFIAPI\r
257 EfiIp4Receive (\r
258   IN EFI_IP4_PROTOCOL         *This,\r
259   IN EFI_IP4_COMPLETION_TOKEN *Token\r
260   );\r
261 \r
262 /**\r
263   Abort an asynchronous transmit or receive request.\r
264 \r
265   The Cancel() function is used to abort a pending transmit or receive request.\r
266   If the token is in the transmit or receive request queues, after calling this\r
267   function, Token->Status will be set to EFI_ABORTED and then Token->Event will\r
268   be signaled. If the token is not in one of the queues, which usually means the\r
269   asynchronous operation has completed, this function will not signal the token\r
270   and EFI_NOT_FOUND is returned.\r
271 \r
272   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.\r
273   @param[in]  Token Pointer to a token that has been issued by\r
274                     EFI_IP4_PROTOCOL.Transmit() or\r
275                     EFI_IP4_PROTOCOL.Receive(). If NULL, all pending\r
276                     tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is\r
277                     defined in EFI_IP4_PROTOCOL.Transmit().\r
278 \r
279   @retval EFI_SUCCESS           The asynchronous I/O request was aborted and\r
280                                 Token.->Event was signaled. When Token is NULL, all\r
281                                 pending requests were aborted and their events were signaled.\r
282   @retval EFI_INVALID_PARAMETER This is NULL.\r
283   @retval EFI_NOT_STARTED       This instance has not been started.\r
284   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
285                                 RARP, etc.) is not finished yet.\r
286   @retval EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was\r
287                                 not found in the transmit or receive queue. It has either completed\r
288                                 or was not issued by Transmit() and Receive().\r
289 \r
290 **/\r
291 EFI_STATUS\r
292 EFIAPI\r
293 EfiIp4Cancel (\r
294   IN EFI_IP4_PROTOCOL         *This,\r
295   IN EFI_IP4_COMPLETION_TOKEN *Token    OPTIONAL\r
296   );\r
297 \r
298 /**\r
299   Polls for incoming data packets and processes outgoing data packets.\r
300 \r
301   The Poll() function polls for incoming data packets and processes outgoing data\r
302   packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()\r
303   function to increase the rate that data packets are moved between the communications\r
304   device and the transmit and receive queues.\r
305 \r
306   In some systems the periodic timer event may not poll the underlying communications\r
307   device fast enough to transmit and/or receive all data packets without missing\r
308   incoming packets or dropping outgoing packets. Drivers and applications that are\r
309   experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function\r
310   more often.\r
311 \r
312   @param[in]  This               Pointer to the EFI_IP4_PROTOCOL instance.\r
313 \r
314   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.\r
315   @retval  EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.\r
316   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
317                                  RARP, etc.) is not finished yet.\r
318   @retval  EFI_INVALID_PARAMETER This is NULL.\r
319   @retval  EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
320   @retval  EFI_NOT_READY         No incoming or outgoing data is processed.\r
321   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.\r
322                                  Consider increasing the polling rate.\r
323 \r
324 **/\r
325 EFI_STATUS\r
326 EFIAPI\r
327 EfiIp4Poll (\r
328   IN EFI_IP4_PROTOCOL       *This\r
329   );\r
330 \r
331 EFI_IP4_PROTOCOL\r
332 mEfiIp4ProtocolTemplete = {\r
333   EfiIp4GetModeData,\r
334   EfiIp4Configure,\r
335   EfiIp4Groups,\r
336   EfiIp4Routes,\r
337   EfiIp4Transmit,\r
338   EfiIp4Receive,\r
339   EfiIp4Cancel,\r
340   EfiIp4Poll\r
341 };\r
342 \r
343 /**\r
344   Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.\r
345 \r
346   The GetModeData() function returns the current operational mode data for this\r
347   driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This\r
348   function is used optionally to retrieve the operational mode data of underlying\r
349   networks or drivers.\r
350 \r
351   @param[in]   This          Pointer to the EFI_IP4_PROTOCOL instance.\r
352   @param[out]  Ip4ModeData   Pointer to the EFI IPv4 Protocol mode data structure.\r
353   @param[out]  MnpConfigData Pointer to the managed network configuration data structure.\r
354   @param[out]  SnpModeData   Pointer to the simple network mode data structure.\r
355 \r
356   @retval EFI_SUCCESS           The operation completed successfully.\r
357   @retval EFI_INVALID_PARAMETER This is NULL.\r
358   @retval EFI_OUT_OF_RESOURCES  The required mode data could not be allocated.\r
359 \r
360 **/\r
361 EFI_STATUS\r
362 EFIAPI\r
363 EfiIp4GetModeData (\r
364   IN  CONST EFI_IP4_PROTOCOL                *This,\r
365   OUT       EFI_IP4_MODE_DATA               *Ip4ModeData     OPTIONAL,\r
366   OUT       EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData   OPTIONAL,\r
367   OUT       EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL\r
368   )\r
369 {\r
370   IP4_PROTOCOL              *IpInstance;\r
371   IP4_SERVICE               *IpSb;\r
372   EFI_IP4_CONFIG_DATA       *Config;\r
373   EFI_STATUS                Status;\r
374   EFI_TPL                   OldTpl;\r
375   IP4_ADDR                  Ip;\r
376 \r
377   if (This == NULL) {\r
378     return EFI_INVALID_PARAMETER;\r
379   }\r
380 \r
381   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
382   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
383   IpSb       = IpInstance->Service;\r
384 \r
385   if (Ip4ModeData != NULL) {\r
386     //\r
387     // IsStarted is "whether the EfiIp4Configure has been called".\r
388     // IsConfigured is "whether the station address has been configured"\r
389     //\r
390     Ip4ModeData->IsStarted     = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);\r
391     CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));\r
392     Ip4ModeData->IsConfigured  = FALSE;\r
393 \r
394     Ip4ModeData->GroupCount    = IpInstance->GroupCount;\r
395     Ip4ModeData->GroupTable    = (EFI_IPv4_ADDRESS *) IpInstance->Groups;\r
396 \r
397     Ip4ModeData->IcmpTypeCount = 23;\r
398     Ip4ModeData->IcmpTypeList  = mIp4SupportedIcmp;\r
399 \r
400     Ip4ModeData->RouteTable    = NULL;\r
401     Ip4ModeData->RouteCount    = 0;\r
402 \r
403     Ip4ModeData->MaxPacketSize = IpSb->MaxPacketSize;\r
404 \r
405     //\r
406     // return the current station address for this IP child. So,\r
407     // the user can get the default address through this. Some\r
408     // application wants to know it station address even it is\r
409     // using the default one, such as a ftp server.\r
410     //\r
411     if (Ip4ModeData->IsStarted) {\r
412       Config  = &Ip4ModeData->ConfigData;\r
413 \r
414       Ip = HTONL (IpInstance->Interface->Ip);\r
415       CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
416 \r
417       Ip = HTONL (IpInstance->Interface->SubnetMask);\r
418       CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
419 \r
420       Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;\r
421 \r
422       //\r
423       // Build a EFI route table for user from the internal route table.\r
424       //\r
425       Status = Ip4BuildEfiRouteTable (IpInstance);\r
426 \r
427       if (EFI_ERROR (Status)) {\r
428         gBS->RestoreTPL (OldTpl);\r
429         return Status;\r
430       }\r
431 \r
432       Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;\r
433       Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;\r
434     }\r
435   }\r
436 \r
437   //\r
438   // Get fresh mode data from MNP, since underlying media status may change\r
439   //\r
440   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);\r
441 \r
442   gBS->RestoreTPL (OldTpl);\r
443   return Status;\r
444 }\r
445 \r
446 \r
447 /**\r
448   Config the MNP parameter used by IP. The IP driver use one MNP\r
449   child to transmit/receive frames. By default, it configures MNP\r
450   to receive unicast/multicast/broadcast. And it will enable/disable\r
451   the promiscous receive according to whether there is IP child\r
452   enable that or not. If Force is FALSE, it will iterate through\r
453   all the IP children to check whether the promiscuous receive\r
454   setting has been changed. If it hasn't been changed, it won't\r
455   reconfigure the MNP. If Force is TRUE, the MNP is configured no\r
456   matter whether that is changed or not.\r
457 \r
458   @param[in]  IpSb               The IP4 service instance that is to be changed.\r
459   @param[in]  Force              Force the configuration or not.\r
460 \r
461   @retval EFI_SUCCESS            The MNP is successfully configured/reconfigured.\r
462   @retval Others                 Configuration failed.\r
463 \r
464 **/\r
465 EFI_STATUS\r
466 Ip4ServiceConfigMnp (\r
467   IN IP4_SERVICE            *IpSb,\r
468   IN BOOLEAN                Force\r
469   )\r
470 {\r
471   LIST_ENTRY                *Entry;\r
472   LIST_ENTRY                *ProtoEntry;\r
473   IP4_INTERFACE             *IpIf;\r
474   IP4_PROTOCOL              *IpInstance;\r
475   BOOLEAN                   Reconfig;\r
476   BOOLEAN                   PromiscReceive;\r
477   EFI_STATUS                Status;\r
478 \r
479   Reconfig       = FALSE;\r
480   PromiscReceive = FALSE;\r
481 \r
482   if (!Force) {\r
483     //\r
484     // Iterate through the IP children to check whether promiscuous\r
485     // receive setting has been changed. Update the interface's receive\r
486     // filter also.\r
487     //\r
488     NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
489 \r
490       IpIf              = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
491       IpIf->PromiscRecv = FALSE;\r
492 \r
493       NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {\r
494         IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);\r
495 \r
496         if (IpInstance->ConfigData.AcceptPromiscuous) {\r
497           IpIf->PromiscRecv = TRUE;\r
498           PromiscReceive    = TRUE;\r
499         }\r
500       }\r
501     }\r
502 \r
503     //\r
504     // If promiscuous receive isn't changed, it isn't necessary to reconfigure.\r
505     //\r
506     if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
507       return EFI_SUCCESS;\r
508     }\r
509 \r
510     Reconfig  = TRUE;\r
511     IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;\r
512   }\r
513 \r
514   Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);\r
515 \r
516   //\r
517   // recover the original configuration if failed to set the configure.\r
518   //\r
519   if (EFI_ERROR (Status) && Reconfig) {\r
520     IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;\r
521   }\r
522 \r
523   return Status;\r
524 }\r
525 \r
526 \r
527 /**\r
528   Intiialize the IP4_PROTOCOL structure to the unconfigured states.\r
529 \r
530   @param  IpSb                   The IP4 service instance.\r
531   @param  IpInstance             The IP4 child instance.\r
532 \r
533 **/\r
534 VOID\r
535 Ip4InitProtocol (\r
536   IN     IP4_SERVICE            *IpSb,\r
537   IN OUT IP4_PROTOCOL           *IpInstance\r
538   )\r
539 {\r
540   ASSERT ((IpSb != NULL) && (IpInstance != NULL));\r
541 \r
542   ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));\r
543 \r
544   IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;\r
545   CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));\r
546   IpInstance->State     = IP4_STATE_UNCONFIGED;\r
547   IpInstance->InDestroy   = FALSE;\r
548   IpInstance->Service   = IpSb;\r
549 \r
550   InitializeListHead (&IpInstance->Link);\r
551   NetMapInit  (&IpInstance->RxTokens);\r
552   NetMapInit  (&IpInstance->TxTokens);\r
553   InitializeListHead (&IpInstance->Received);\r
554   InitializeListHead (&IpInstance->Delivered);\r
555   InitializeListHead (&IpInstance->AddrLink);\r
556 \r
557   EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);\r
558 }\r
559 \r
560 \r
561 /**\r
562   Configure the IP4 child. If the child is already configured,\r
563   change the configuration parameter. Otherwise configure it\r
564   for the first time. The caller should validate the configuration\r
565   before deliver them to it. It also don't do configure NULL.\r
566 \r
567   @param[in, out]  IpInstance         The IP4 child to configure.\r
568   @param[in]       Config             The configure data.\r
569 \r
570   @retval EFI_SUCCESS            The IP4 child is successfully configured.\r
571   @retval EFI_DEVICE_ERROR       Failed to free the pending transive or to\r
572                                  configure  underlying MNP or other errors.\r
573   @retval EFI_NO_MAPPING         The IP4 child is configured to use default\r
574                                  address, but the default address hasn't been\r
575                                  configured. The IP4 child doesn't need to be\r
576                                  reconfigured when default address is configured.\r
577   @retval EFI_OUT_OF_RESOURCES   No more memory space is available.\r
578   @retval other                  Other error occurs.\r
579 \r
580 **/\r
581 EFI_STATUS\r
582 Ip4ConfigProtocol (\r
583   IN OUT IP4_PROTOCOL         *IpInstance,\r
584   IN     EFI_IP4_CONFIG_DATA  *Config\r
585   )\r
586 {\r
587   IP4_SERVICE               *IpSb;\r
588   IP4_INTERFACE             *IpIf;\r
589   EFI_STATUS                Status;\r
590   IP4_ADDR                  Ip;\r
591   IP4_ADDR                  Netmask;\r
592   EFI_ARP_PROTOCOL          *Arp;\r
593   EFI_IP4_CONFIG2_PROTOCOL  *Ip4Config2;\r
594   EFI_IP4_CONFIG2_POLICY    Policy;\r
595 \r
596   IpSb = IpInstance->Service;\r
597 \r
598   Ip4Config2  = NULL;\r
599 \r
600   //\r
601   // User is changing packet filters. It must be stopped\r
602   // before the station address can be changed.\r
603   //\r
604   if (IpInstance->State == IP4_STATE_CONFIGED) {\r
605     //\r
606     // Cancel all the pending transmit/receive from upper layer\r
607     //\r
608     Status = Ip4Cancel (IpInstance, NULL);\r
609 \r
610     if (EFI_ERROR (Status)) {\r
611       return EFI_DEVICE_ERROR;\r
612     }\r
613 \r
614     CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
615     return EFI_SUCCESS;\r
616   }\r
617 \r
618   //\r
619   // Configure a fresh IP4 protocol instance. Create a route table.\r
620   // Each IP child has its own route table, which may point to the\r
621   // default table if it is using default address.\r
622   //\r
623   Status                 = EFI_OUT_OF_RESOURCES;\r
624   IpInstance->RouteTable = Ip4CreateRouteTable ();\r
625 \r
626   if (IpInstance->RouteTable == NULL) {\r
627     return Status;\r
628   }\r
629 \r
630   //\r
631   // Set up the interface.\r
632   //\r
633   CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));\r
634   CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));\r
635 \r
636   Ip      = NTOHL (Ip);\r
637   Netmask = NTOHL (Netmask);\r
638 \r
639   if (!Config->UseDefaultAddress) {\r
640     //\r
641     // Find whether there is already an interface with the same\r
642     // station address. All the instances with the same station\r
643     // address shares one interface.\r
644     //\r
645     IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);\r
646 \r
647     if (IpIf != NULL) {\r
648       NET_GET_REF (IpIf);\r
649 \r
650     } else {\r
651       IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
652 \r
653       if (IpIf == NULL) {\r
654         goto ON_ERROR;\r
655       }\r
656 \r
657       Status = Ip4SetAddress (IpIf, Ip, Netmask);\r
658 \r
659       if (EFI_ERROR (Status)) {\r
660         Status = EFI_DEVICE_ERROR;\r
661         Ip4FreeInterface (IpIf, IpInstance);\r
662         goto ON_ERROR;\r
663       }\r
664 \r
665       InsertTailList (&IpSb->Interfaces, &IpIf->Link);\r
666     }\r
667 \r
668     //\r
669     // Add a route to this connected network in the instance route table.\r
670     //\r
671     Ip4AddRoute (\r
672       IpInstance->RouteTable,\r
673       Ip & Netmask,\r
674       Netmask,\r
675       IP4_ALLZERO_ADDRESS\r
676       );\r
677   } else {\r
678     //\r
679     // Use the default address. Check the state.\r
680     //\r
681     if (IpSb->State == IP4_SERVICE_UNSTARTED) {\r
682       //\r
683       // Trigger the EFI_IP4_CONFIG2_PROTOCOL to retrieve the\r
684       // default IPv4 address if it is not available yet.\r
685       //\r
686       Policy = IpSb->Ip4Config2Instance.Policy;\r
687       if (Policy != Ip4Config2PolicyDhcp) {\r
688         Ip4Config2 = &IpSb->Ip4Config2Instance.Ip4Config2;\r
689         Policy = Ip4Config2PolicyDhcp;\r
690         Status= Ip4Config2->SetData (\r
691                               Ip4Config2,\r
692                               Ip4Config2DataTypePolicy,\r
693                               sizeof (EFI_IP4_CONFIG2_POLICY),\r
694                               &Policy\r
695                               );\r
696         if (EFI_ERROR (Status)) {\r
697           goto ON_ERROR;\r
698         }\r
699       }\r
700     }\r
701 \r
702     IpIf = IpSb->DefaultInterface;\r
703     NET_GET_REF (IpSb->DefaultInterface);\r
704 \r
705     //\r
706     // If default address is used, so is the default route table.\r
707     // Any route set by the instance has the precedence over the\r
708     // routes in the default route table. Link the default table\r
709     // after the instance's table. Routing will search the local\r
710     // table first.\r
711     //\r
712     NET_GET_REF (IpSb->DefaultRouteTable);\r
713     IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;\r
714   }\r
715 \r
716   IpInstance->Interface = IpIf;\r
717   if (IpIf->Arp != NULL) {\r
718     Arp = NULL;\r
719     Status = gBS->OpenProtocol (\r
720                     IpIf->ArpHandle,\r
721                     &gEfiArpProtocolGuid,\r
722                     (VOID **) &Arp,\r
723                     gIp4DriverBinding.DriverBindingHandle,\r
724                     IpInstance->Handle,\r
725                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
726                     );\r
727     if (EFI_ERROR (Status)) {\r
728       Ip4FreeInterface (IpIf, IpInstance);\r
729       goto ON_ERROR;\r
730     }\r
731   }\r
732   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);\r
733 \r
734   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
735   IpInstance->State       = IP4_STATE_CONFIGED;\r
736 \r
737   //\r
738   // Although EFI_NO_MAPPING is an error code, the IP child has been\r
739   // successfully configured and doesn't need reconfiguration when\r
740   // default address is acquired.\r
741   //\r
742   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
743     return EFI_NO_MAPPING;\r
744   }\r
745 \r
746   return EFI_SUCCESS;\r
747 \r
748 ON_ERROR:\r
749   Ip4FreeRouteTable (IpInstance->RouteTable);\r
750   IpInstance->RouteTable = NULL;\r
751   return Status;\r
752 }\r
753 \r
754 \r
755 /**\r
756   Clean up the IP4 child, release all the resources used by it.\r
757 \r
758   @param[in]  IpInstance         The IP4 child to clean up.\r
759 \r
760   @retval EFI_SUCCESS            The IP4 child is cleaned up.\r
761   @retval EFI_DEVICE_ERROR       Some resources failed to be released.\r
762 \r
763 **/\r
764 EFI_STATUS\r
765 Ip4CleanProtocol (\r
766   IN  IP4_PROTOCOL          *IpInstance\r
767   )\r
768 {\r
769   if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {\r
770     return EFI_DEVICE_ERROR;\r
771   }\r
772 \r
773   if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {\r
774     return EFI_DEVICE_ERROR;\r
775   }\r
776 \r
777   //\r
778   // Some packets haven't been recycled. It is because either the\r
779   // user forgets to recycle the packets, or because the callback\r
780   // hasn't been called. Just leave it alone.\r
781   //\r
782   if (!IsListEmpty (&IpInstance->Delivered)) {\r
783     ;\r
784   }\r
785 \r
786   if (IpInstance->Interface != NULL) {\r
787     RemoveEntryList (&IpInstance->AddrLink);\r
788     if (IpInstance->Interface->Arp != NULL) {\r
789       gBS->CloseProtocol (\r
790              IpInstance->Interface->ArpHandle,\r
791              &gEfiArpProtocolGuid,\r
792              gIp4DriverBinding.DriverBindingHandle,\r
793              IpInstance->Handle\r
794              );\r
795     }\r
796     Ip4FreeInterface (IpInstance->Interface, IpInstance);\r
797     IpInstance->Interface = NULL;\r
798   }\r
799 \r
800   if (IpInstance->RouteTable != NULL) {\r
801     if (IpInstance->RouteTable->Next != NULL) {\r
802       Ip4FreeRouteTable (IpInstance->RouteTable->Next);\r
803     }\r
804 \r
805     Ip4FreeRouteTable (IpInstance->RouteTable);\r
806     IpInstance->RouteTable = NULL;\r
807   }\r
808 \r
809   if (IpInstance->EfiRouteTable != NULL) {\r
810     FreePool (IpInstance->EfiRouteTable);\r
811     IpInstance->EfiRouteTable = NULL;\r
812     IpInstance->EfiRouteCount = 0;\r
813   }\r
814 \r
815   if (IpInstance->Groups != NULL) {\r
816     FreePool (IpInstance->Groups);\r
817     IpInstance->Groups      = NULL;\r
818     IpInstance->GroupCount  = 0;\r
819   }\r
820 \r
821   NetMapClean (&IpInstance->TxTokens);\r
822 \r
823   NetMapClean (&IpInstance->RxTokens);\r
824 \r
825   return EFI_SUCCESS;\r
826 }\r
827 \r
828 \r
829 /**\r
830   Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.\r
831 \r
832   The Configure() function is used to set, change, or reset the operational\r
833   parameters and filter settings for this EFI IPv4 Protocol instance. Until these\r
834   parameters have been set, no network traffic can be sent or received by this\r
835   instance. Once the parameters have been reset (by calling this function with\r
836   IpConfigData set to NULL), no more traffic can be sent or received until these\r
837   parameters have been set again. Each EFI IPv4 Protocol instance can be started\r
838   and stopped independently of each other by enabling or disabling their receive\r
839   filter settings with the Configure() function.\r
840 \r
841   When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will\r
842   be appended as an alias address into the addresses list in the EFI IPv4 Protocol\r
843   driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL\r
844   to retrieve the default IPv4 address if it is not available yet. Clients could\r
845   frequently call GetModeData() to check the status to ensure that the default IPv4\r
846   address is ready.\r
847 \r
848   If operational parameters are reset or changed, any pending transmit and receive\r
849   requests will be cancelled. Their completion token status will be set to EFI_ABORTED\r
850   and their events will be signaled.\r
851 \r
852   @param[in]  This              Pointer to the EFI_IP4_PROTOCOL instance.\r
853   @param[in]  IpConfigData      Pointer to the EFI IPv4 Protocol configuration data structure.\r
854 \r
855   @retval EFI_SUCCESS           The driver instance was successfully opened.\r
856   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
857                                 RARP, etc.) is not finished yet.\r
858   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
859   @retval EFI_UNSUPPORTED       One or more of the following conditions is TRUE:\r
860                                 A configuration protocol (DHCP, BOOTP, RARP, etc.) could\r
861                                 not be located when clients choose to use the default IPv4\r
862                                 address. This EFI IPv4 Protocol implementation does not\r
863                                 support this requested filter or timeout setting.\r
864   @retval EFI_OUT_OF_RESOURCES  The EFI IPv4 Protocol driver instance data could not be allocated.\r
865   @retval EFI_ALREADY_STARTED   The interface is already open and must be stopped before the\r
866                                 IPv4 address or subnet mask can be changed. The interface must\r
867                                 also be stopped when switching to/from raw packet mode.\r
868   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred. The EFI IPv4\r
869                                 Protocol driver instance is not opened.\r
870 \r
871 **/\r
872 EFI_STATUS\r
873 EFIAPI\r
874 EfiIp4Configure (\r
875   IN EFI_IP4_PROTOCOL       *This,\r
876   IN EFI_IP4_CONFIG_DATA    *IpConfigData       OPTIONAL\r
877   )\r
878 {\r
879   IP4_PROTOCOL              *IpInstance;\r
880   EFI_IP4_CONFIG_DATA       *Current;\r
881   EFI_TPL                   OldTpl;\r
882   EFI_STATUS                Status;\r
883   BOOLEAN                   AddrOk;\r
884   IP4_ADDR                  IpAddress;\r
885   IP4_ADDR                  SubnetMask;\r
886 \r
887   //\r
888   // First, validate the parameters\r
889   //\r
890   if (This == NULL) {\r
891     return EFI_INVALID_PARAMETER;\r
892   }\r
893 \r
894   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
895   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
896 \r
897   //\r
898   // Validate the configuration first.\r
899   //\r
900   if (IpConfigData != NULL) {\r
901 \r
902     CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));\r
903     CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));\r
904 \r
905     IpAddress  = NTOHL (IpAddress);\r
906     SubnetMask = NTOHL (SubnetMask);\r
907 \r
908     //\r
909     // Check whether the station address is a valid unicast address\r
910     //\r
911     if (!IpConfigData->UseDefaultAddress) {\r
912       AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);\r
913 \r
914       if (!AddrOk) {\r
915         Status = EFI_INVALID_PARAMETER;\r
916         goto ON_EXIT;\r
917       }\r
918     }\r
919 \r
920     //\r
921     // User can only update packet filters when already configured.\r
922     // If it wants to change the station address, it must configure(NULL)\r
923     // the instance first.\r
924     //\r
925     if (IpInstance->State == IP4_STATE_CONFIGED) {\r
926       Current = &IpInstance->ConfigData;\r
927 \r
928       if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {\r
929         Status = EFI_ALREADY_STARTED;\r
930         goto ON_EXIT;\r
931       }\r
932 \r
933       if (!Current->UseDefaultAddress &&\r
934          (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||\r
935           !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {\r
936         Status = EFI_ALREADY_STARTED;\r
937         goto ON_EXIT;\r
938       }\r
939 \r
940       if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
941         Status = EFI_NO_MAPPING;\r
942         goto ON_EXIT;\r
943       }\r
944     }\r
945   }\r
946 \r
947   //\r
948   // Configure the instance or clean it up.\r
949   //\r
950   if (IpConfigData != NULL) {\r
951     Status = Ip4ConfigProtocol (IpInstance, IpConfigData);\r
952   } else {\r
953     Status = Ip4CleanProtocol (IpInstance);\r
954 \r
955     //\r
956     // Consider the following valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,\r
957     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,\r
958     // the unload fails miserably.\r
959     //\r
960     if (IpInstance->State == IP4_STATE_CONFIGED) {\r
961       IpInstance->State = IP4_STATE_UNCONFIGED;\r
962     }\r
963   }\r
964 \r
965   //\r
966   // Update the MNP's configure data. Ip4ServiceConfigMnp will check\r
967   // whether it is necessary to reconfigure the MNP.\r
968   //\r
969   Ip4ServiceConfigMnp (IpInstance->Service, FALSE);\r
970 \r
971 ON_EXIT:\r
972   gBS->RestoreTPL (OldTpl);\r
973   return Status;\r
974 \r
975 }\r
976 \r
977 \r
978 /**\r
979   Change the IP4 child's multicast setting. The caller\r
980   should make sure that the parameters is valid.\r
981 \r
982   @param[in]  IpInstance             The IP4 child to change the setting.\r
983   @param[in]  JoinFlag               TRUE to join the group, otherwise leave it.\r
984   @param[in]  GroupAddress           The target group address.\r
985 \r
986   @retval EFI_ALREADY_STARTED    Want to join the group, but already a member of it.\r
987   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.\r
988   @retval EFI_DEVICE_ERROR       Failed to set the group configuraton.\r
989   @retval EFI_SUCCESS            Successfully updated the group setting.\r
990   @retval EFI_NOT_FOUND          Try to leave the group which it isn't a member.\r
991 \r
992 **/\r
993 EFI_STATUS\r
994 Ip4Groups (\r
995   IN IP4_PROTOCOL           *IpInstance,\r
996   IN BOOLEAN                JoinFlag,\r
997   IN EFI_IPv4_ADDRESS       *GroupAddress       OPTIONAL\r
998   )\r
999 {\r
1000   IP4_ADDR                  *Members;\r
1001   IP4_ADDR                  Group;\r
1002   UINT32                    Index;\r
1003 \r
1004   //\r
1005   // Add it to the instance's Groups, and join the group by IGMP.\r
1006   // IpInstance->Groups is in network byte order. IGMP operates in\r
1007   // host byte order\r
1008   //\r
1009   if (JoinFlag) {\r
1010     //\r
1011     // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.\r
1012     //\r
1013     ASSERT (GroupAddress != NULL);\r
1014     CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));\r
1015 \r
1016     for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
1017       if (IpInstance->Groups[Index] == Group) {\r
1018         return EFI_ALREADY_STARTED;\r
1019       }\r
1020     }\r
1021 \r
1022     Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);\r
1023 \r
1024     if (Members == NULL) {\r
1025       return EFI_OUT_OF_RESOURCES;\r
1026     }\r
1027 \r
1028     if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {\r
1029       FreePool (Members);\r
1030       return EFI_DEVICE_ERROR;\r
1031     }\r
1032 \r
1033     if (IpInstance->Groups != NULL) {\r
1034       FreePool (IpInstance->Groups);\r
1035     }\r
1036 \r
1037     IpInstance->Groups = Members;\r
1038     IpInstance->GroupCount++;\r
1039 \r
1040     return EFI_SUCCESS;\r
1041   }\r
1042 \r
1043   //\r
1044   // Leave the group. Leave all the groups if GroupAddress is NULL.\r
1045   // Must iterate from the end to the beginning because the GroupCount\r
1046   // is decreamented each time an address is removed..\r
1047   //\r
1048   for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {\r
1049     ASSERT (IpInstance->Groups != NULL);\r
1050     Group = IpInstance->Groups[Index - 1];\r
1051     if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {\r
1052       if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {\r
1053         return EFI_DEVICE_ERROR;\r
1054       }\r
1055 \r
1056       Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);\r
1057       IpInstance->GroupCount--;\r
1058 \r
1059       if (IpInstance->GroupCount == 0) {\r
1060         ASSERT (Index == 1);\r
1061 \r
1062         FreePool (IpInstance->Groups);\r
1063         IpInstance->Groups = NULL;\r
1064       }\r
1065 \r
1066       if (GroupAddress != NULL) {\r
1067         return EFI_SUCCESS;\r
1068       }\r
1069     }\r
1070   }\r
1071 \r
1072   return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);\r
1073 }\r
1074 \r
1075 \r
1076 /**\r
1077   Joins and leaves multicast groups.\r
1078 \r
1079   The Groups() function is used to join and leave multicast group sessions. Joining\r
1080   a group will enable reception of matching multicast packets. Leaving a group will\r
1081   disable the multicast packet reception.\r
1082 \r
1083   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.\r
1084 \r
1085   @param[in]  This                  Pointer to the EFI_IP4_PROTOCOL instance.\r
1086   @param[in]  JoinFlag              Set to TRUE to join the multicast group session and FALSE to leave.\r
1087   @param[in]  GroupAddress          Pointer to the IPv4 multicast address.\r
1088 \r
1089   @retval EFI_SUCCESS           The operation completed successfully.\r
1090   @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:\r
1091                                 - This is NULL.\r
1092                                 - JoinFlag is TRUE and GroupAddress is NULL.\r
1093                                 - GroupAddress is not NULL and *GroupAddress is\r
1094                                 not a multicast IPv4 address.\r
1095   @retval EFI_NOT_STARTED       This instance has not been started.\r
1096   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
1097                                 RARP, etc.) is not finished yet.\r
1098   @retval EFI_OUT_OF_RESOURCES  System resources could not be allocated.\r
1099   @retval EFI_UNSUPPORTED       This EFI IPv4 Protocol implementation does not support multicast groups.\r
1100   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when\r
1101                                 JoinFlag is TRUE).\r
1102   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is FALSE).\r
1103   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
1104 \r
1105 **/\r
1106 EFI_STATUS\r
1107 EFIAPI\r
1108 EfiIp4Groups (\r
1109   IN EFI_IP4_PROTOCOL       *This,\r
1110   IN BOOLEAN                JoinFlag,\r
1111   IN EFI_IPv4_ADDRESS       *GroupAddress     OPTIONAL\r
1112   )\r
1113 {\r
1114   IP4_PROTOCOL              *IpInstance;\r
1115   EFI_STATUS                Status;\r
1116   EFI_TPL                   OldTpl;\r
1117   IP4_ADDR                  McastIp;\r
1118 \r
1119   if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {\r
1120     return EFI_INVALID_PARAMETER;\r
1121   }\r
1122 \r
1123   if (GroupAddress != NULL) {\r
1124     CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));\r
1125 \r
1126     if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {\r
1127       return EFI_INVALID_PARAMETER;\r
1128     }\r
1129   }\r
1130 \r
1131   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1132   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
1133 \r
1134   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1135     Status = EFI_NOT_STARTED;\r
1136     goto ON_EXIT;\r
1137   }\r
1138 \r
1139   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
1140     Status = EFI_NO_MAPPING;\r
1141     goto ON_EXIT;\r
1142   }\r
1143 \r
1144   Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);\r
1145 \r
1146 ON_EXIT:\r
1147   gBS->RestoreTPL (OldTpl);\r
1148   return Status;\r
1149 }\r
1150 \r
1151 \r
1152 /**\r
1153   Adds and deletes routing table entries.\r
1154 \r
1155   The Routes() function adds a route to or deletes a route from the routing table.\r
1156 \r
1157   Routes are determined by comparing the SubnetAddress with the destination IPv4\r
1158   address arithmetically AND-ed with the SubnetMask. The gateway address must be\r
1159   on the same subnet as the configured station address.\r
1160 \r
1161   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.\r
1162   The default route matches all destination IPv4 addresses that do not match any\r
1163   other routes.\r
1164 \r
1165   A GatewayAddress that is zero is a nonroute. Packets are sent to the destination\r
1166   IP address if it can be found in the ARP cache or on the local subnet. One automatic\r
1167   nonroute entry will be inserted into the routing table for outgoing packets that\r
1168   are addressed to a local subnet (gateway address of 0.0.0.0).\r
1169 \r
1170   Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI\r
1171   IPv4 Protocol instances that use the default IPv4 address will also have copies\r
1172   of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these\r
1173   copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its\r
1174   instances. As a result, client modification to the routing table will be lost.\r
1175 \r
1176   @param[in]  This                   Pointer to the EFI_IP4_PROTOCOL instance.\r
1177   @param[in]  DeleteRoute            Set to TRUE to delete this route from the routing table. Set to\r
1178                                      FALSE to add this route to the routing table. SubnetAddress\r
1179                                      and SubnetMask are used as the key to each route entry.\r
1180   @param[in]  SubnetAddress          The address of the subnet that needs to be routed.\r
1181   @param[in]  SubnetMask             The subnet mask of SubnetAddress.\r
1182   @param[in]  GatewayAddress         The unicast gateway IPv4 address for this route.\r
1183 \r
1184   @retval EFI_SUCCESS            The operation completed successfully.\r
1185   @retval EFI_NOT_STARTED        The driver instance has not been started.\r
1186   @retval EFI_NO_MAPPING         When using the default address, configuration (DHCP, BOOTP,\r
1187                                  RARP, etc.) is not finished yet.\r
1188   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
1189                                  - This is NULL.\r
1190                                  - SubnetAddress is NULL.\r
1191                                  - SubnetMask is NULL.\r
1192                                  - GatewayAddress is NULL.\r
1193                                  - *SubnetAddress is not a valid subnet address.\r
1194                                  - *SubnetMask is not a valid subnet mask.\r
1195                                  - *GatewayAddress is not a valid unicast IPv4 address.\r
1196   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.\r
1197   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).\r
1198   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when\r
1199                                   DeleteRoute is FALSE).\r
1200 \r
1201 **/\r
1202 EFI_STATUS\r
1203 EFIAPI\r
1204 EfiIp4Routes (\r
1205   IN EFI_IP4_PROTOCOL       *This,\r
1206   IN BOOLEAN                DeleteRoute,\r
1207   IN EFI_IPv4_ADDRESS       *SubnetAddress,\r
1208   IN EFI_IPv4_ADDRESS       *SubnetMask,\r
1209   IN EFI_IPv4_ADDRESS       *GatewayAddress\r
1210   )\r
1211 {\r
1212   IP4_PROTOCOL              *IpInstance;\r
1213   IP4_INTERFACE             *IpIf;\r
1214   IP4_ADDR                  Dest;\r
1215   IP4_ADDR                  Netmask;\r
1216   IP4_ADDR                  Nexthop;\r
1217   EFI_STATUS                Status;\r
1218   EFI_TPL                   OldTpl;\r
1219 \r
1220   //\r
1221   // First, validate the parameters\r
1222   //\r
1223   if ((This == NULL) || (SubnetAddress == NULL) ||\r
1224       (SubnetMask == NULL) || (GatewayAddress == NULL)) {\r
1225     return EFI_INVALID_PARAMETER;\r
1226   }\r
1227 \r
1228   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1229   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
1230 \r
1231   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1232     Status = EFI_NOT_STARTED;\r
1233     goto ON_EXIT;\r
1234   }\r
1235 \r
1236   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
1237     Status = EFI_NO_MAPPING;\r
1238     goto ON_EXIT;\r
1239   }\r
1240 \r
1241   CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));\r
1242   CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));\r
1243   CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));\r
1244 \r
1245   Dest    = NTOHL (Dest);\r
1246   Netmask = NTOHL (Netmask);\r
1247   Nexthop = NTOHL (Nexthop);\r
1248 \r
1249   IpIf    = IpInstance->Interface;\r
1250 \r
1251   if (!IP4_IS_VALID_NETMASK (Netmask)) {\r
1252     Status = EFI_INVALID_PARAMETER;\r
1253     goto ON_EXIT;\r
1254   }\r
1255 \r
1256   //\r
1257   // the gateway address must be a unicast on the connected network if not zero.\r
1258   //\r
1259   if ((Nexthop != IP4_ALLZERO_ADDRESS) &&\r
1260       ((IpIf->SubnetMask != IP4_ALLONE_ADDRESS && !IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask)) ||\r
1261         IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {\r
1262 \r
1263     Status = EFI_INVALID_PARAMETER;\r
1264     goto ON_EXIT;\r
1265   }\r
1266 \r
1267   if (DeleteRoute) {\r
1268     Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);\r
1269   } else {\r
1270     Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);\r
1271   }\r
1272 \r
1273 ON_EXIT:\r
1274   gBS->RestoreTPL (OldTpl);\r
1275   return Status;\r
1276 }\r
1277 \r
1278 \r
1279 /**\r
1280   Check whether the user's token or event has already\r
1281   been enqueued on IP4's list.\r
1282 \r
1283   @param[in]  Map                    The container of either user's transmit or receive\r
1284                                      token.\r
1285   @param[in]  Item                   Current item to check against.\r
1286   @param[in]  Context                The Token to check againist.\r
1287 \r
1288   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP.\r
1289   @retval EFI_SUCCESS            The current item isn't the same token/event as the\r
1290                                  context.\r
1291 \r
1292 **/\r
1293 EFI_STATUS\r
1294 EFIAPI\r
1295 Ip4TokenExist (\r
1296   IN NET_MAP                *Map,\r
1297   IN NET_MAP_ITEM           *Item,\r
1298   IN VOID                   *Context\r
1299   )\r
1300 {\r
1301   EFI_IP4_COMPLETION_TOKEN  *Token;\r
1302   EFI_IP4_COMPLETION_TOKEN  *TokenInItem;\r
1303 \r
1304   Token       = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
1305   TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;\r
1306 \r
1307   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
1308     return EFI_ACCESS_DENIED;\r
1309   }\r
1310 \r
1311   return EFI_SUCCESS;\r
1312 }\r
1313 \r
1314 /**\r
1315   Validate the user's token against current station address.\r
1316 \r
1317   @param[in]  Token              User's token to validate.\r
1318   @param[in]  IpIf               The IP4 child's interface.\r
1319   @param[in]  RawData            Set to TRUE to send unformatted packets.\r
1320 \r
1321   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
1322   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.\r
1323   @retval EFI_SUCCESS            The token is valid.\r
1324 \r
1325 **/\r
1326 EFI_STATUS\r
1327 Ip4TxTokenValid (\r
1328   IN EFI_IP4_COMPLETION_TOKEN   *Token,\r
1329   IN IP4_INTERFACE              *IpIf,\r
1330   IN BOOLEAN                    RawData\r
1331   )\r
1332 {\r
1333   EFI_IP4_TRANSMIT_DATA     *TxData;\r
1334   EFI_IP4_OVERRIDE_DATA     *Override;\r
1335   IP4_ADDR                  Src;\r
1336   IP4_ADDR                  Gateway;\r
1337   UINT32                    Offset;\r
1338   UINT32                    Index;\r
1339   UINT32                    HeadLen;\r
1340 \r
1341   if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {\r
1342     return EFI_INVALID_PARAMETER;\r
1343   }\r
1344 \r
1345   TxData = Token->Packet.TxData;\r
1346 \r
1347   //\r
1348   // Check the fragment table: no empty fragment, and length isn't bogus.\r
1349   //\r
1350   if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {\r
1351     return EFI_INVALID_PARAMETER;\r
1352   }\r
1353 \r
1354   Offset = TxData->TotalDataLength;\r
1355 \r
1356   if (Offset > IP4_MAX_PACKET_SIZE) {\r
1357     return EFI_BAD_BUFFER_SIZE;\r
1358   }\r
1359 \r
1360   for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
1361     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||\r
1362         (TxData->FragmentTable[Index].FragmentLength == 0)) {\r
1363 \r
1364       return EFI_INVALID_PARAMETER;\r
1365     }\r
1366 \r
1367     Offset -= TxData->FragmentTable[Index].FragmentLength;\r
1368   }\r
1369 \r
1370   if (Offset != 0) {\r
1371     return EFI_INVALID_PARAMETER;\r
1372   }\r
1373 \r
1374   //\r
1375   // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData\r
1376   // is TRUE.\r
1377   //\r
1378   if (RawData) {\r
1379     return EFI_SUCCESS;\r
1380   }\r
1381 \r
1382   //\r
1383   // Check the IP options: no more than 40 bytes and format is OK\r
1384   //\r
1385   if (TxData->OptionsLength != 0) {\r
1386     if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {\r
1387       return EFI_INVALID_PARAMETER;\r
1388     }\r
1389 \r
1390     if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {\r
1391       return EFI_INVALID_PARAMETER;\r
1392     }\r
1393   }\r
1394 \r
1395   //\r
1396   // Check the source and gateway: they must be a valid unicast.\r
1397   // Gateway must also be on the connected network.\r
1398   //\r
1399   if (TxData->OverrideData != NULL) {\r
1400     Override = TxData->OverrideData;\r
1401 \r
1402     CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
1403     CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
1404 \r
1405     Src     = NTOHL (Src);\r
1406     Gateway = NTOHL (Gateway);\r
1407 \r
1408     if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||\r
1409         (Src == IP4_ALLONE_ADDRESS) ||\r
1410         IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
1411 \r
1412       return EFI_INVALID_PARAMETER;\r
1413     }\r
1414 \r
1415     //\r
1416     // If gateway isn't zero, it must be a unicast address, and\r
1417     // on the connected network.\r
1418     //\r
1419     if ((Gateway != IP4_ALLZERO_ADDRESS) &&\r
1420         ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||\r
1421          !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||\r
1422          IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {\r
1423 \r
1424       return EFI_INVALID_PARAMETER;\r
1425     }\r
1426   }\r
1427 \r
1428   //\r
1429   // Check the packet length: Head length and packet length all has a limit\r
1430   //\r
1431   HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);\r
1432 \r
1433   if ((HeadLen > IP4_MAX_HEADLEN) ||\r
1434       (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {\r
1435 \r
1436     return EFI_BAD_BUFFER_SIZE;\r
1437   }\r
1438 \r
1439   return EFI_SUCCESS;\r
1440 }\r
1441 \r
1442 \r
1443 /**\r
1444   The callback function for the net buffer which wraps the user's\r
1445   transmit token. Although it seems this function is pretty simple,\r
1446   there are some subtle things.\r
1447   When user requests the IP to transmit a packet by passing it a\r
1448   token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data\r
1449   is wrapped in an net buffer. the net buffer's Free function is\r
1450   set to Ip4FreeTxToken. The Token and token wrap are added to the\r
1451   IP child's TxToken map. Then the buffer is passed to Ip4Output for\r
1452   transmission. If something error happened before that, the buffer\r
1453   is freed, which in turn will free the token wrap. The wrap may\r
1454   have been added to the TxToken map or not, and the user's event\r
1455   shouldn't be fired because we are still in the EfiIp4Transmit. If\r
1456   the buffer has been sent by Ip4Output, it should be removed from\r
1457   the TxToken map and user's event signaled. The token wrap and buffer\r
1458   are bound together. Check the comments in Ip4Output for information\r
1459   about IP fragmentation.\r
1460 \r
1461   @param[in]  Context                The token's wrap.\r
1462 \r
1463 **/\r
1464 VOID\r
1465 EFIAPI\r
1466 Ip4FreeTxToken (\r
1467   IN VOID                   *Context\r
1468   )\r
1469 {\r
1470   IP4_TXTOKEN_WRAP          *Wrap;\r
1471   NET_MAP_ITEM              *Item;\r
1472 \r
1473   Wrap = (IP4_TXTOKEN_WRAP *) Context;\r
1474 \r
1475   //\r
1476   // Signal IpSecRecycleEvent to inform IPsec free the memory\r
1477   //\r
1478   if (Wrap->IpSecRecycleSignal != NULL) {\r
1479     gBS->SignalEvent (Wrap->IpSecRecycleSignal);\r
1480   }\r
1481 \r
1482   //\r
1483   // Find the token in the instance's map. EfiIp4Transmit put the\r
1484   // token to the map. If that failed, NetMapFindKey will return NULL.\r
1485   //\r
1486   Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);\r
1487 \r
1488   if (Item != NULL) {\r
1489     NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);\r
1490   }\r
1491 \r
1492   if (Wrap->Sent) {\r
1493     gBS->SignalEvent (Wrap->Token->Event);\r
1494 \r
1495     //\r
1496     // Dispatch the DPC queued by the NotifyFunction of Token->Event.\r
1497     //\r
1498     DispatchDpc ();\r
1499   }\r
1500 \r
1501   FreePool (Wrap);\r
1502 }\r
1503 \r
1504 \r
1505 /**\r
1506   The callback function to Ip4Output to update the transmit status.\r
1507 \r
1508   @param  Ip4Instance            The Ip4Instance that request the transmit.\r
1509   @param  Packet                 The user's transmit request.\r
1510   @param  IoStatus               The result of the transmission.\r
1511   @param  Flag                   Not used during transmission.\r
1512   @param  Context                The token's wrap.\r
1513 \r
1514 **/\r
1515 VOID\r
1516 Ip4OnPacketSent (\r
1517   IP4_PROTOCOL              *Ip4Instance,\r
1518   NET_BUF                   *Packet,\r
1519   EFI_STATUS                IoStatus,\r
1520   UINT32                    Flag,\r
1521   VOID                      *Context\r
1522   )\r
1523 {\r
1524   IP4_TXTOKEN_WRAP          *Wrap;\r
1525 \r
1526   //\r
1527   // This is the transmission request from upper layer,\r
1528   // not the IP4 driver itself.\r
1529   //\r
1530   ASSERT (Ip4Instance != NULL);\r
1531 \r
1532   //\r
1533   // The first fragment of the packet has been sent. Update\r
1534   // the token's status. That is, if fragmented, the transmit's\r
1535   // status is the first fragment's status. The Wrap will be\r
1536   // release when all the fragments are release. Check the comments\r
1537   // in Ip4FreeTxToken and Ip4Output for information.\r
1538   //\r
1539   Wrap                = (IP4_TXTOKEN_WRAP *) Context;\r
1540   Wrap->Token->Status = IoStatus;\r
1541 \r
1542   NetbufFree (Wrap->Packet);\r
1543 }\r
1544 \r
1545 \r
1546 /**\r
1547   Places outgoing data packets into the transmit queue.\r
1548 \r
1549   The Transmit() function places a sending request in the transmit queue of this\r
1550   EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some\r
1551   errors occur, the event in the token will be signaled and the status is updated.\r
1552 \r
1553   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.\r
1554   @param[in]  Token Pointer to the transmit token.\r
1555 \r
1556   @retval  EFI_SUCCESS           The data has been queued for transmission.\r
1557   @retval  EFI_NOT_STARTED       This instance has not been started.\r
1558   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
1559                                  RARP, etc.) is not finished yet.\r
1560   @retval  EFI_INVALID_PARAMETER One or more pameters are invalid.\r
1561   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.Event\r
1562                                  was already in the transmit queue.\r
1563   @retval  EFI_NOT_READY         The completion token could not be queued because the transmit\r
1564                                  queue is full.\r
1565   @retval  EFI_NOT_FOUND         Not route is found to destination address.\r
1566   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.\r
1567   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too\r
1568                                  short to transmit.\r
1569   @retval  EFI_BAD_BUFFER_SIZE   The length of the IPv4 header + option length + total data length is\r
1570                                  greater than MTU (or greater than the maximum packet size if\r
1571                                  Token.Packet.TxData.OverrideData.\r
1572                                  DoNotFragment is TRUE).\r
1573 \r
1574 **/\r
1575 EFI_STATUS\r
1576 EFIAPI\r
1577 EfiIp4Transmit (\r
1578   IN EFI_IP4_PROTOCOL         *This,\r
1579   IN EFI_IP4_COMPLETION_TOKEN *Token\r
1580   )\r
1581 {\r
1582   IP4_SERVICE               *IpSb;\r
1583   IP4_PROTOCOL              *IpInstance;\r
1584   IP4_INTERFACE             *IpIf;\r
1585   IP4_TXTOKEN_WRAP          *Wrap;\r
1586   EFI_IP4_TRANSMIT_DATA     *TxData;\r
1587   EFI_IP4_CONFIG_DATA       *Config;\r
1588   EFI_IP4_OVERRIDE_DATA     *Override;\r
1589   IP4_HEAD                  Head;\r
1590   IP4_ADDR                  GateWay;\r
1591   EFI_STATUS                Status;\r
1592   EFI_TPL                   OldTpl;\r
1593   BOOLEAN                   DontFragment;\r
1594   UINT32                    HeadLen;\r
1595   UINT8                     RawHdrLen;\r
1596   UINT32                    OptionsLength;\r
1597   UINT8                     *OptionsBuffer;\r
1598   VOID                      *FirstFragment;\r
1599 \r
1600   if (This == NULL) {\r
1601     return EFI_INVALID_PARAMETER;\r
1602   }\r
1603 \r
1604   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1605 \r
1606   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1607     return EFI_NOT_STARTED;\r
1608   }\r
1609 \r
1610   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
1611 \r
1612   IpSb    = IpInstance->Service;\r
1613   IpIf    = IpInstance->Interface;\r
1614   Config  = &IpInstance->ConfigData;\r
1615 \r
1616   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
1617     Status = EFI_NO_MAPPING;\r
1618     goto ON_EXIT;\r
1619   }\r
1620 \r
1621   //\r
1622   // make sure that token is properly formated\r
1623   //\r
1624   Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);\r
1625 \r
1626   if (EFI_ERROR (Status)) {\r
1627     goto ON_EXIT;\r
1628   }\r
1629 \r
1630   //\r
1631   // Check whether the token or signal already existed.\r
1632   //\r
1633   if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {\r
1634     Status = EFI_ACCESS_DENIED;\r
1635     goto ON_EXIT;\r
1636   }\r
1637 \r
1638   //\r
1639   // Build the IP header, need to fill in the Tos, TotalLen, Id,\r
1640   // fragment, Ttl, protocol, Src, and Dst.\r
1641   //\r
1642   TxData = Token->Packet.TxData;\r
1643 \r
1644   FirstFragment = NULL;\r
1645 \r
1646   if (Config->RawData) {\r
1647     //\r
1648     // When RawData is TRUE, first buffer in FragmentTable points to a raw\r
1649     // IPv4 fragment including IPv4 header and options.\r
1650     //\r
1651     FirstFragment = TxData->FragmentTable[0].FragmentBuffer;\r
1652     CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));\r
1653 \r
1654     RawHdrLen = (UINT8) (RawHdrLen & 0x0f);\r
1655     if (RawHdrLen < 5) {\r
1656       Status = EFI_INVALID_PARAMETER;\r
1657       goto ON_EXIT;\r
1658     }\r
1659 \r
1660     RawHdrLen = (UINT8) (RawHdrLen << 2);\r
1661 \r
1662     CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);\r
1663 \r
1664     Ip4NtohHead (&Head);\r
1665     HeadLen      = 0;\r
1666     DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);\r
1667 \r
1668     if (!DontFragment) {\r
1669       Status = EFI_INVALID_PARAMETER;\r
1670       goto ON_EXIT;\r
1671     }\r
1672 \r
1673     GateWay = IP4_ALLZERO_ADDRESS;\r
1674 \r
1675     //\r
1676     // Get IPv4 options from first fragment.\r
1677     //\r
1678     if (RawHdrLen == IP4_MIN_HEADLEN) {\r
1679       OptionsLength = 0;\r
1680       OptionsBuffer = NULL;\r
1681     } else {\r
1682       OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;\r
1683       OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;\r
1684     }\r
1685 \r
1686     //\r
1687     // Trim off IPv4 header and options from first fragment.\r
1688     //\r
1689     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;\r
1690     TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;\r
1691   } else {\r
1692     CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));\r
1693     Head.Dst = NTOHL (Head.Dst);\r
1694 \r
1695     if (TxData->OverrideData != NULL) {\r
1696       Override      = TxData->OverrideData;\r
1697       Head.Protocol = Override->Protocol;\r
1698       Head.Tos      = Override->TypeOfService;\r
1699       Head.Ttl      = Override->TimeToLive;\r
1700       DontFragment  = Override->DoNotFragment;\r
1701 \r
1702       CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
1703       CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
1704 \r
1705       Head.Src = NTOHL (Head.Src);\r
1706       GateWay  = NTOHL (GateWay);\r
1707     } else {\r
1708       Head.Src      = IpIf->Ip;\r
1709       GateWay       = IP4_ALLZERO_ADDRESS;\r
1710       Head.Protocol = Config->DefaultProtocol;\r
1711       Head.Tos      = Config->TypeOfService;\r
1712       Head.Ttl      = Config->TimeToLive;\r
1713       DontFragment  = Config->DoNotFragment;\r
1714     }\r
1715 \r
1716     Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);\r
1717     HeadLen       = (TxData->OptionsLength + 3) & (~0x03);\r
1718 \r
1719     OptionsLength = TxData->OptionsLength;\r
1720     OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);\r
1721   }\r
1722 \r
1723   //\r
1724   // If don't fragment and fragment needed, return error\r
1725   //\r
1726   if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {\r
1727     Status = EFI_BAD_BUFFER_SIZE;\r
1728     goto ON_EXIT;\r
1729   }\r
1730 \r
1731   //\r
1732   // OK, it survives all the validation check. Wrap the token in\r
1733   // a IP4_TXTOKEN_WRAP and the data in a netbuf\r
1734   //\r
1735   Status = EFI_OUT_OF_RESOURCES;\r
1736   Wrap   = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));\r
1737   if (Wrap == NULL) {\r
1738     goto ON_EXIT;\r
1739   }\r
1740 \r
1741   Wrap->IpInstance  = IpInstance;\r
1742   Wrap->Token       = Token;\r
1743   Wrap->Sent        = FALSE;\r
1744   Wrap->Life        = IP4_US_TO_SEC (Config->TransmitTimeout);\r
1745   Wrap->Packet      = NetbufFromExt (\r
1746                         (NET_FRAGMENT *) TxData->FragmentTable,\r
1747                         TxData->FragmentCount,\r
1748                         IP4_MAX_HEADLEN,\r
1749                         0,\r
1750                         Ip4FreeTxToken,\r
1751                         Wrap\r
1752                         );\r
1753 \r
1754   if (Wrap->Packet == NULL) {\r
1755     FreePool (Wrap);\r
1756     goto ON_EXIT;\r
1757   }\r
1758 \r
1759   Token->Status = EFI_NOT_READY;\r
1760 \r
1761   if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {\r
1762     //\r
1763     // NetbufFree will call Ip4FreeTxToken, which in turn will\r
1764     // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been\r
1765     // enqueued.\r
1766     //\r
1767     if (Config->RawData) {\r
1768       //\r
1769       // Restore pointer of first fragment in RawData mode.\r
1770       //\r
1771       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;\r
1772     }\r
1773 \r
1774     NetbufFree (Wrap->Packet);\r
1775     goto ON_EXIT;\r
1776   }\r
1777 \r
1778   //\r
1779   // Mark the packet sent before output it. Mark it not sent again if the\r
1780   // returned status is not EFI_SUCCESS;\r
1781   //\r
1782   Wrap->Sent = TRUE;\r
1783 \r
1784   Status = Ip4Output (\r
1785              IpSb,\r
1786              IpInstance,\r
1787              Wrap->Packet,\r
1788              &Head,\r
1789              OptionsBuffer,\r
1790              OptionsLength,\r
1791              GateWay,\r
1792              Ip4OnPacketSent,\r
1793              Wrap\r
1794              );\r
1795 \r
1796   if (EFI_ERROR (Status)) {\r
1797     Wrap->Sent = FALSE;\r
1798 \r
1799     if (Config->RawData) {\r
1800       //\r
1801       // Restore pointer of first fragment in RawData mode.\r
1802       //\r
1803       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;\r
1804     }\r
1805 \r
1806     NetbufFree (Wrap->Packet);\r
1807   }\r
1808 \r
1809   if (Config->RawData) {\r
1810     //\r
1811     // Restore pointer of first fragment in RawData mode.\r
1812     //\r
1813     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;\r
1814   }\r
1815 \r
1816 ON_EXIT:\r
1817   gBS->RestoreTPL (OldTpl);\r
1818   return Status;\r
1819 }\r
1820 \r
1821 \r
1822 /**\r
1823   Places a receiving request into the receiving queue.\r
1824 \r
1825   The Receive() function places a completion token into the receive packet queue.\r
1826   This function is always asynchronous.\r
1827 \r
1828   The Token.Event field in the completion token must be filled in by the caller\r
1829   and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol\r
1830   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event\r
1831   is signaled.\r
1832 \r
1833   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.\r
1834   @param[in]  Token Pointer to a token that is associated with the receive data descriptor.\r
1835 \r
1836   @retval EFI_SUCCESS           The receive completion token was cached.\r
1837   @retval EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.\r
1838   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP, RARP, etc.)\r
1839                                 is not finished yet.\r
1840   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
1841                                 - This is NULL.\r
1842                                 - Token is NULL.\r
1843                                 - Token.Event is NULL.\r
1844   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system\r
1845                                 resources (usually memory).\r
1846   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
1847                                 The EFI IPv4 Protocol instance has been reset to startup defaults.\r
1848                                 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already\r
1849                                 in the receive queue.\r
1850   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.\r
1851   @retval EFI_ICMP_ERROR        An ICMP error packet was received.\r
1852 \r
1853 **/\r
1854 EFI_STATUS\r
1855 EFIAPI\r
1856 EfiIp4Receive (\r
1857   IN EFI_IP4_PROTOCOL         *This,\r
1858   IN EFI_IP4_COMPLETION_TOKEN *Token\r
1859   )\r
1860 {\r
1861   IP4_PROTOCOL              *IpInstance;\r
1862   EFI_STATUS                Status;\r
1863   EFI_TPL                   OldTpl;\r
1864 \r
1865   //\r
1866   // First validate the parameters\r
1867   //\r
1868   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {\r
1869     return EFI_INVALID_PARAMETER;\r
1870   }\r
1871 \r
1872   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1873 \r
1874   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1875 \r
1876   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1877     Status = EFI_NOT_STARTED;\r
1878     goto ON_EXIT;\r
1879   }\r
1880 \r
1881   //\r
1882   // Check whether the toke is already on the receive queue.\r
1883   //\r
1884   Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);\r
1885 \r
1886   if (EFI_ERROR (Status)) {\r
1887     Status = EFI_ACCESS_DENIED;\r
1888     goto ON_EXIT;\r
1889   }\r
1890 \r
1891   //\r
1892   // Queue the token then check whether there is pending received packet.\r
1893   //\r
1894   Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);\r
1895 \r
1896   if (EFI_ERROR (Status)) {\r
1897     goto ON_EXIT;\r
1898   }\r
1899 \r
1900   Status = Ip4InstanceDeliverPacket (IpInstance);\r
1901 \r
1902   //\r
1903   // Dispatch the DPC queued by the NotifyFunction of this instane's receive\r
1904   // event.\r
1905   //\r
1906   DispatchDpc ();\r
1907 \r
1908 ON_EXIT:\r
1909   gBS->RestoreTPL (OldTpl);\r
1910   return Status;\r
1911 }\r
1912 \r
1913 \r
1914 /**\r
1915   Cancel the transmitted but not recycled packet. If a matching\r
1916   token is found, it will call Ip4CancelPacket to cancel the\r
1917   packet. Ip4CancelPacket will cancel all the fragments of the\r
1918   packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP\r
1919   will be deleted from the Map, and user's event signalled.\r
1920   Because Ip4CancelPacket and other functions are all called in\r
1921   line, so, after Ip4CancelPacket returns, the Item has been freed.\r
1922 \r
1923   @param[in]  Map                The IP4 child's transmit queue.\r
1924   @param[in]  Item               The current transmitted packet to test.\r
1925   @param[in]  Context            The user's token to cancel.\r
1926 \r
1927   @retval EFI_SUCCESS            Continue to check the next Item.\r
1928   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.\r
1929 \r
1930 **/\r
1931 EFI_STATUS\r
1932 EFIAPI\r
1933 Ip4CancelTxTokens (\r
1934   IN NET_MAP                *Map,\r
1935   IN NET_MAP_ITEM           *Item,\r
1936   IN VOID                   *Context\r
1937   )\r
1938 {\r
1939   EFI_IP4_COMPLETION_TOKEN  *Token;\r
1940   IP4_TXTOKEN_WRAP          *Wrap;\r
1941 \r
1942   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
1943 \r
1944   //\r
1945   // Return EFI_SUCCESS to check the next item in the map if\r
1946   // this one doesn't match.\r
1947   //\r
1948   if ((Token != NULL) && (Token != Item->Key)) {\r
1949     return EFI_SUCCESS;\r
1950   }\r
1951 \r
1952   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;\r
1953   ASSERT (Wrap != NULL);\r
1954 \r
1955   //\r
1956   // Don't access the Item, Wrap and Token's members after this point.\r
1957   // Item and wrap has been freed. And we no longer own the Token.\r
1958   //\r
1959   Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
1960 \r
1961   //\r
1962   // If only one item is to be cancel, return EFI_ABORTED to stop\r
1963   // iterating the map any more.\r
1964   //\r
1965   if (Token != NULL) {\r
1966     return EFI_ABORTED;\r
1967   }\r
1968 \r
1969   return EFI_SUCCESS;\r
1970 }\r
1971 \r
1972 \r
1973 /**\r
1974   Cancel the receive request. This is quiet simple, because\r
1975   it is only enqueued in our local receive map.\r
1976 \r
1977   @param[in]  Map                The IP4 child's receive queue.\r
1978   @param[in]  Item               Current receive request to cancel.\r
1979   @param[in]  Context            The user's token to cancel.\r
1980 \r
1981   @retval EFI_SUCCESS            Continue to check the next receive request on the\r
1982                                  queue.\r
1983   @retval EFI_ABORTED            The user's token (token != NULL) has been\r
1984                                  cancelled.\r
1985 \r
1986 **/\r
1987 EFI_STATUS\r
1988 EFIAPI\r
1989 Ip4CancelRxTokens (\r
1990   IN NET_MAP                *Map,\r
1991   IN NET_MAP_ITEM           *Item,\r
1992   IN VOID                   *Context\r
1993   )\r
1994 {\r
1995   EFI_IP4_COMPLETION_TOKEN  *Token;\r
1996   EFI_IP4_COMPLETION_TOKEN  *This;\r
1997 \r
1998   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
1999   This  = Item->Key;\r
2000 \r
2001   if ((Token != NULL) && (Token != This)) {\r
2002     return EFI_SUCCESS;\r
2003   }\r
2004 \r
2005   NetMapRemoveItem (Map, Item, NULL);\r
2006 \r
2007   This->Status        = EFI_ABORTED;\r
2008   This->Packet.RxData = NULL;\r
2009   gBS->SignalEvent (This->Event);\r
2010 \r
2011   if (Token != NULL) {\r
2012     return EFI_ABORTED;\r
2013   }\r
2014 \r
2015   return EFI_SUCCESS;\r
2016 }\r
2017 \r
2018 \r
2019 /**\r
2020   Cancel the user's receive/transmit request.\r
2021 \r
2022   @param[in]  IpInstance         The IP4 child.\r
2023   @param[in]  Token              The token to cancel. If NULL, all token will be\r
2024                                  cancelled.\r
2025 \r
2026   @retval EFI_SUCCESS            The token is cancelled.\r
2027   @retval EFI_NOT_FOUND          The token isn't found on either the\r
2028                                  transmit/receive queue.\r
2029   @retval EFI_DEVICE_ERROR       Not all token is cancelled when Token is NULL.\r
2030 \r
2031 **/\r
2032 EFI_STATUS\r
2033 Ip4Cancel (\r
2034   IN IP4_PROTOCOL             *IpInstance,\r
2035   IN EFI_IP4_COMPLETION_TOKEN *Token          OPTIONAL\r
2036   )\r
2037 {\r
2038   EFI_STATUS                Status;\r
2039 \r
2040   //\r
2041   // First check the transmitted packet. Ip4CancelTxTokens returns\r
2042   // EFI_ABORTED to mean that the token has been cancelled when\r
2043   // token != NULL. So, return EFI_SUCCESS for this condition.\r
2044   //\r
2045   Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);\r
2046 \r
2047   if (EFI_ERROR (Status)) {\r
2048     if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
2049       return EFI_SUCCESS;\r
2050     }\r
2051 \r
2052     return Status;\r
2053   }\r
2054 \r
2055   //\r
2056   // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT\r
2057   // for Token!=NULL and it is cancelled.\r
2058   //\r
2059   Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);\r
2060   //\r
2061   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's\r
2062   // events.\r
2063   //\r
2064   DispatchDpc ();\r
2065   if (EFI_ERROR (Status)) {\r
2066     if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
2067       return EFI_SUCCESS;\r
2068     }\r
2069 \r
2070     return Status;\r
2071   }\r
2072 \r
2073   //\r
2074   // OK, if the Token is found when Token != NULL, the NetMapIterate\r
2075   // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.\r
2076   //\r
2077   if (Token != NULL) {\r
2078     return EFI_NOT_FOUND;\r
2079   }\r
2080 \r
2081   //\r
2082   // If Token == NULL, cancel all the tokens. return error if no\r
2083   // all of them are cancelled.\r
2084   //\r
2085   if (!NetMapIsEmpty (&IpInstance->TxTokens) ||\r
2086       !NetMapIsEmpty (&IpInstance->RxTokens)) {\r
2087 \r
2088     return EFI_DEVICE_ERROR;\r
2089   }\r
2090 \r
2091   return EFI_SUCCESS;\r
2092 }\r
2093 \r
2094 \r
2095 /**\r
2096   Abort an asynchronous transmit or receive request.\r
2097 \r
2098   The Cancel() function is used to abort a pending transmit or receive request.\r
2099   If the token is in the transmit or receive request queues, after calling this\r
2100   function, Token->Status will be set to EFI_ABORTED and then Token->Event will\r
2101   be signaled. If the token is not in one of the queues, which usually means the\r
2102   asynchronous operation has completed, this function will not signal the token\r
2103   and EFI_NOT_FOUND is returned.\r
2104 \r
2105   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.\r
2106   @param[in]  Token Pointer to a token that has been issued by\r
2107                     EFI_IP4_PROTOCOL.Transmit() or\r
2108                     EFI_IP4_PROTOCOL.Receive(). If NULL, all pending\r
2109                     tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is\r
2110                     defined in EFI_IP4_PROTOCOL.Transmit().\r
2111 \r
2112   @retval EFI_SUCCESS           The asynchronous I/O request was aborted and\r
2113                                 Token.->Event was signaled. When Token is NULL, all\r
2114                                 pending requests were aborted and their events were signaled.\r
2115   @retval EFI_INVALID_PARAMETER This is NULL.\r
2116   @retval EFI_NOT_STARTED       This instance has not been started.\r
2117   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
2118                                 RARP, etc.) is not finished yet.\r
2119   @retval EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was\r
2120                                 not found in the transmit or receive queue. It has either completed\r
2121                                 or was not issued by Transmit() and Receive().\r
2122 \r
2123 **/\r
2124 EFI_STATUS\r
2125 EFIAPI\r
2126 EfiIp4Cancel (\r
2127   IN EFI_IP4_PROTOCOL         *This,\r
2128   IN EFI_IP4_COMPLETION_TOKEN *Token    OPTIONAL\r
2129   )\r
2130 {\r
2131   IP4_PROTOCOL              *IpInstance;\r
2132   EFI_STATUS                Status;\r
2133   EFI_TPL                   OldTpl;\r
2134 \r
2135   if (This == NULL) {\r
2136     return EFI_INVALID_PARAMETER;\r
2137   }\r
2138 \r
2139   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
2140 \r
2141   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2142 \r
2143   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
2144     Status = EFI_NOT_STARTED;\r
2145     goto ON_EXIT;\r
2146   }\r
2147 \r
2148   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
2149     Status = EFI_NO_MAPPING;\r
2150     goto ON_EXIT;\r
2151   }\r
2152 \r
2153   Status = Ip4Cancel (IpInstance, Token);\r
2154 \r
2155 ON_EXIT:\r
2156   gBS->RestoreTPL (OldTpl);\r
2157   return Status;\r
2158 }\r
2159 \r
2160 \r
2161 /**\r
2162   Polls for incoming data packets and processes outgoing data packets.\r
2163 \r
2164   The Poll() function polls for incoming data packets and processes outgoing data\r
2165   packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()\r
2166   function to increase the rate that data packets are moved between the communications\r
2167   device and the transmit and receive queues.\r
2168 \r
2169   In some systems the periodic timer event may not poll the underlying communications\r
2170   device fast enough to transmit and/or receive all data packets without missing\r
2171   incoming packets or dropping outgoing packets. Drivers and applications that are\r
2172   experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function\r
2173   more often.\r
2174 \r
2175   @param[in]  This               Pointer to the EFI_IP4_PROTOCOL instance.\r
2176 \r
2177   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.\r
2178   @retval  EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.\r
2179   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,\r
2180                                  RARP, etc.) is not finished yet.\r
2181   @retval  EFI_INVALID_PARAMETER This is NULL.\r
2182   @retval  EFI_DEVICE_ERROR      An unexpected system or network error occurred.\r
2183   @retval  EFI_NOT_READY         No incoming or outgoing data is processed.\r
2184   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.\r
2185                                  Consider increasing the polling rate.\r
2186 \r
2187 **/\r
2188 EFI_STATUS\r
2189 EFIAPI\r
2190 EfiIp4Poll (\r
2191   IN EFI_IP4_PROTOCOL       *This\r
2192   )\r
2193 {\r
2194   IP4_PROTOCOL                  *IpInstance;\r
2195   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;\r
2196 \r
2197   if (This == NULL) {\r
2198     return EFI_INVALID_PARAMETER;\r
2199   }\r
2200 \r
2201   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
2202 \r
2203   if (IpInstance->State == IP4_STATE_UNCONFIGED) {\r
2204     return EFI_NOT_STARTED;\r
2205   }\r
2206 \r
2207   Mnp = IpInstance->Service->Mnp;\r
2208 \r
2209   //\r
2210   // Don't lock the Poll function to enable the deliver of\r
2211   // the packet polled up.\r
2212   //\r
2213   return Mnp->Poll (Mnp);\r
2214 }\r
2215 \r
2216 /**\r
2217   Decrease the life of the transmitted packets. If it is\r
2218   decreased to zero, cancel the packet. This function is\r
2219   called by Ip4PacketTimerTicking which time out both the\r
2220   received-but-not-delivered and transmitted-but-not-recycle\r
2221   packets.\r
2222 \r
2223   @param[in]  Map                    The IP4 child's transmit map.\r
2224   @param[in]  Item                   Current transmitted packet.\r
2225   @param[in]  Context                Not used.\r
2226 \r
2227   @retval EFI_SUCCESS            Always returns EFI_SUCCESS.\r
2228 \r
2229 **/\r
2230 EFI_STATUS\r
2231 EFIAPI\r
2232 Ip4SentPacketTicking (\r
2233   IN NET_MAP                *Map,\r
2234   IN NET_MAP_ITEM           *Item,\r
2235   IN VOID                   *Context\r
2236   )\r
2237 {\r
2238   IP4_TXTOKEN_WRAP          *Wrap;\r
2239 \r
2240   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;\r
2241   ASSERT (Wrap != NULL);\r
2242 \r
2243   if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {\r
2244     Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
2245   }\r
2246 \r
2247   return EFI_SUCCESS;\r
2248 }\r
2249 \r
2250 /**\r
2251   This heart beat timer of IP4 service instance times out all of its IP4 children's\r
2252   received-but-not-delivered and transmitted-but-not-recycle packets, and provides\r
2253   time input for its IGMP protocol.\r
2254 \r
2255   @param[in]  Event                  The IP4 service instance's heart beat timer.\r
2256   @param[in]  Context                The IP4 service instance.\r
2257 \r
2258 **/\r
2259 VOID\r
2260 EFIAPI\r
2261 Ip4TimerTicking (\r
2262   IN EFI_EVENT              Event,\r
2263   IN VOID                   *Context\r
2264   )\r
2265 {\r
2266   IP4_SERVICE               *IpSb;\r
2267 \r
2268   IpSb = (IP4_SERVICE *) Context;\r
2269   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
2270 \r
2271   Ip4PacketTimerTicking (IpSb);\r
2272   Ip4IgmpTicking (IpSb);\r
2273 }\r
2274 \r
2275 /**\r
2276   This dedicated timer is used to poll underlying network media status. In case\r
2277   of cable swap or wireless network switch, a new round auto configuration will\r
2278   be initiated. The timer will signal the IP4 to run DHCP configuration again.\r
2279   IP4 driver will free old IP address related resource, such as route table and\r
2280   Interface, then initiate a DHCP process to acquire new IP, eventually create\r
2281   route table for new IP address.\r
2282 \r
2283   @param[in]  Event                  The IP4 service instance's heart beat timer.\r
2284   @param[in]  Context                The IP4 service instance.\r
2285 \r
2286 **/\r
2287 VOID\r
2288 EFIAPI\r
2289 Ip4TimerReconfigChecking (\r
2290   IN EFI_EVENT              Event,\r
2291   IN VOID                   *Context\r
2292   )\r
2293 {\r
2294   IP4_SERVICE               *IpSb;\r
2295   BOOLEAN                   OldMediaPresent;\r
2296   EFI_STATUS                Status;\r
2297   EFI_SIMPLE_NETWORK_MODE   SnpModeData;\r
2298 \r
2299   IpSb = (IP4_SERVICE *) Context;\r
2300   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
2301 \r
2302   OldMediaPresent = IpSb->MediaPresent;\r
2303 \r
2304   //\r
2305   // Get fresh mode data from MNP, since underlying media status may change.\r
2306   // Here, it needs to mention that the MediaPresent can also be checked even if\r
2307   // EFI_NOT_STARTED returned while this MNP child driver instance isn't configured.\r
2308   //\r
2309   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &SnpModeData);\r
2310   if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
2311     return;\r
2312   }\r
2313 \r
2314   IpSb->MediaPresent = SnpModeData.MediaPresent;\r
2315   //\r
2316   // Media transimit Unpresent to Present means new link movement is detected.\r
2317   //\r
2318   if (!OldMediaPresent && IpSb->MediaPresent && (IpSb->Ip4Config2Instance.Policy == Ip4Config2PolicyDhcp)) {\r
2319     //\r
2320     // Signal the IP4 to run the dhcp configuration again. IP4 driver will free\r
2321     // old IP address related resource, such as route table and Interface, then\r
2322     // initiate a DHCP round to acquire new IP, eventually\r
2323     // create route table for new IP address.\r
2324     //\r
2325     if (IpSb->ReconfigEvent != NULL) {\r
2326       Status = gBS->SignalEvent (IpSb->ReconfigEvent);\r
2327       DispatchDpc ();\r
2328     }\r
2329   }\r
2330 }\r