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