• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3 Copyright (c) 2005 - 2016, 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   Configure the IP4 child. If the child is already configured,
568   change the configuration parameter. Otherwise configure it
569   for the first time. The caller should validate the configuration
570   before deliver them to it. It also don't do configure NULL.
571 
572   @param[in, out]  IpInstance         The IP4 child to configure.
573   @param[in]       Config             The configure data.
574 
575   @retval EFI_SUCCESS            The IP4 child is successfully configured.
576   @retval EFI_DEVICE_ERROR       Failed to free the pending transive or to
577                                  configure  underlying MNP or other errors.
578   @retval EFI_NO_MAPPING         The IP4 child is configured to use default
579                                  address, but the default address hasn't been
580                                  configured. The IP4 child doesn't need to be
581                                  reconfigured when default address is configured.
582   @retval EFI_OUT_OF_RESOURCES   No more memory space is available.
583   @retval other                  Other error occurs.
584 
585 **/
586 EFI_STATUS
Ip4ConfigProtocol(IN OUT IP4_PROTOCOL * IpInstance,IN EFI_IP4_CONFIG_DATA * Config)587 Ip4ConfigProtocol (
588   IN OUT IP4_PROTOCOL         *IpInstance,
589   IN     EFI_IP4_CONFIG_DATA  *Config
590   )
591 {
592   IP4_SERVICE               *IpSb;
593   IP4_INTERFACE             *IpIf;
594   EFI_STATUS                Status;
595   IP4_ADDR                  Ip;
596   IP4_ADDR                  Netmask;
597   EFI_ARP_PROTOCOL          *Arp;
598 
599   IpSb = IpInstance->Service;
600 
601   //
602   // User is changing packet filters. It must be stopped
603   // before the station address can be changed.
604   //
605   if (IpInstance->State == IP4_STATE_CONFIGED) {
606     //
607     // Cancel all the pending transmit/receive from upper layer
608     //
609     Status = Ip4Cancel (IpInstance, NULL);
610 
611     if (EFI_ERROR (Status)) {
612       return EFI_DEVICE_ERROR;
613     }
614 
615     CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
616     return EFI_SUCCESS;
617   }
618 
619   //
620   // Configure a fresh IP4 protocol instance. Create a route table.
621   // Each IP child has its own route table, which may point to the
622   // default table if it is using default address.
623   //
624   Status                 = EFI_OUT_OF_RESOURCES;
625   IpInstance->RouteTable = Ip4CreateRouteTable ();
626 
627   if (IpInstance->RouteTable == NULL) {
628     return Status;
629   }
630 
631   //
632   // Set up the interface.
633   //
634   CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
635   CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
636 
637   Ip      = NTOHL (Ip);
638   Netmask = NTOHL (Netmask);
639 
640   if (!Config->UseDefaultAddress) {
641     //
642     // Find whether there is already an interface with the same
643     // station address. All the instances with the same station
644     // address shares one interface.
645     //
646     IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
647 
648     if (IpIf != NULL) {
649       NET_GET_REF (IpIf);
650 
651     } else {
652       IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
653 
654       if (IpIf == NULL) {
655         goto ON_ERROR;
656       }
657 
658       Status = Ip4SetAddress (IpIf, Ip, Netmask);
659 
660       if (EFI_ERROR (Status)) {
661         Status = EFI_DEVICE_ERROR;
662         Ip4FreeInterface (IpIf, IpInstance);
663         goto ON_ERROR;
664       }
665 
666       InsertTailList (&IpSb->Interfaces, &IpIf->Link);
667     }
668 
669     //
670     // Add a route to this connected network in the route table
671     //
672     Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
673 
674   } else {
675     //
676     // Use the default address. Check the state.
677     //
678     if (IpSb->State == IP4_SERVICE_UNSTARTED) {
679       Status = Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
680 
681       if (EFI_ERROR (Status)) {
682         goto ON_ERROR;
683       }
684     }
685 
686     IpIf = IpSb->DefaultInterface;
687     NET_GET_REF (IpSb->DefaultInterface);
688 
689     //
690     // If default address is used, so is the default route table.
691     // Any route set by the instance has the precedence over the
692     // routes in the default route table. Link the default table
693     // after the instance's table. Routing will search the local
694     // table first.
695     //
696     NET_GET_REF (IpSb->DefaultRouteTable);
697     IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
698   }
699 
700   IpInstance->Interface = IpIf;
701   if (IpIf->Arp != NULL) {
702     Arp = NULL;
703     Status = gBS->OpenProtocol (
704                     IpIf->ArpHandle,
705                     &gEfiArpProtocolGuid,
706                     (VOID **) &Arp,
707                     gIp4DriverBinding.DriverBindingHandle,
708                     IpInstance->Handle,
709                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
710                     );
711     if (EFI_ERROR (Status)) {
712       goto ON_ERROR;
713     }
714   }
715   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
716 
717   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
718   IpInstance->State       = IP4_STATE_CONFIGED;
719 
720   //
721   // Although EFI_NO_MAPPING is an error code, the IP child has been
722   // successfully configured and doesn't need reconfiguration when
723   // default address is acquired.
724   //
725   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
726     return EFI_NO_MAPPING;
727   }
728 
729   return EFI_SUCCESS;
730 
731 ON_ERROR:
732   Ip4FreeRouteTable (IpInstance->RouteTable);
733   IpInstance->RouteTable = NULL;
734   return Status;
735 }
736 
737 
738 /**
739   Clean up the IP4 child, release all the resources used by it.
740 
741   @param[in]  IpInstance         The IP4 child to clean up.
742 
743   @retval EFI_SUCCESS            The IP4 child is cleaned up.
744   @retval EFI_DEVICE_ERROR       Some resources failed to be released.
745 
746 **/
747 EFI_STATUS
Ip4CleanProtocol(IN IP4_PROTOCOL * IpInstance)748 Ip4CleanProtocol (
749   IN  IP4_PROTOCOL          *IpInstance
750   )
751 {
752   if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
753     return EFI_DEVICE_ERROR;
754   }
755 
756   if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
757     return EFI_DEVICE_ERROR;
758   }
759 
760   //
761   // Some packets haven't been recycled. It is because either the
762   // user forgets to recycle the packets, or because the callback
763   // hasn't been called. Just leave it alone.
764   //
765   if (!IsListEmpty (&IpInstance->Delivered)) {
766     ;
767   }
768 
769   if (IpInstance->Interface != NULL) {
770     RemoveEntryList (&IpInstance->AddrLink);
771     if (IpInstance->Interface->Arp != NULL) {
772       gBS->CloseProtocol (
773              IpInstance->Interface->ArpHandle,
774              &gEfiArpProtocolGuid,
775              gIp4DriverBinding.DriverBindingHandle,
776              IpInstance->Handle
777              );
778     }
779     Ip4FreeInterface (IpInstance->Interface, IpInstance);
780     IpInstance->Interface = NULL;
781   }
782 
783   if (IpInstance->RouteTable != NULL) {
784     if (IpInstance->RouteTable->Next != NULL) {
785       Ip4FreeRouteTable (IpInstance->RouteTable->Next);
786     }
787 
788     Ip4FreeRouteTable (IpInstance->RouteTable);
789     IpInstance->RouteTable = NULL;
790   }
791 
792   if (IpInstance->EfiRouteTable != NULL) {
793     FreePool (IpInstance->EfiRouteTable);
794     IpInstance->EfiRouteTable = NULL;
795     IpInstance->EfiRouteCount = 0;
796   }
797 
798   if (IpInstance->Groups != NULL) {
799     FreePool (IpInstance->Groups);
800     IpInstance->Groups      = NULL;
801     IpInstance->GroupCount  = 0;
802   }
803 
804   NetMapClean (&IpInstance->TxTokens);
805 
806   NetMapClean (&IpInstance->RxTokens);
807 
808   return EFI_SUCCESS;
809 }
810 
811 
812 /**
813   Validate that Ip/Netmask pair is OK to be used as station
814   address. Only continuous netmasks are supported. and check
815   that StationAddress is a unicast address on the newtwork.
816 
817   @param[in]  Ip                 The IP address to validate.
818   @param[in]  Netmask            The netmaks of the IP.
819 
820   @retval TRUE                   The Ip/Netmask pair is valid.
821   @retval FALSE                  The Ip/Netmask pair is invalid.
822 
823 **/
824 BOOLEAN
Ip4StationAddressValid(IN IP4_ADDR Ip,IN IP4_ADDR Netmask)825 Ip4StationAddressValid (
826   IN IP4_ADDR               Ip,
827   IN IP4_ADDR               Netmask
828   )
829 {
830   IP4_ADDR                  NetBrdcastMask;
831   INTN                      Len;
832   INTN                      Type;
833 
834   //
835   // Only support the station address with 0.0.0.0/0 to enable DHCP client.
836   //
837   if (Netmask == IP4_ALLZERO_ADDRESS) {
838     return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
839   }
840 
841   //
842   // Only support the continuous net masks
843   //
844   if ((Len = NetGetMaskLength (Netmask)) == (IP4_MASK_MAX + 1)) {
845     return FALSE;
846   }
847 
848   //
849   // Station address can't be class D or class E address
850   //
851   if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
852     return FALSE;
853   }
854 
855   //
856   // Station address can't be subnet broadcast/net broadcast address
857   //
858   if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
859     return FALSE;
860   }
861 
862   NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];
863 
864   if (Ip == (Ip | ~NetBrdcastMask)) {
865     return FALSE;
866   }
867 
868   return TRUE;
869 }
870 
871 
872 /**
873   Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
874 
875   The Configure() function is used to set, change, or reset the operational
876   parameters and filter settings for this EFI IPv4 Protocol instance. Until these
877   parameters have been set, no network traffic can be sent or received by this
878   instance. Once the parameters have been reset (by calling this function with
879   IpConfigData set to NULL), no more traffic can be sent or received until these
880   parameters have been set again. Each EFI IPv4 Protocol instance can be started
881   and stopped independently of each other by enabling or disabling their receive
882   filter settings with the Configure() function.
883 
884   When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
885   be appended as an alias address into the addresses list in the EFI IPv4 Protocol
886   driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
887   to retrieve the default IPv4 address if it is not available yet. Clients could
888   frequently call GetModeData() to check the status to ensure that the default IPv4
889   address is ready.
890 
891   If operational parameters are reset or changed, any pending transmit and receive
892   requests will be cancelled. Their completion token status will be set to EFI_ABORTED
893   and their events will be signaled.
894 
895   @param[in]  This              Pointer to the EFI_IP4_PROTOCOL instance.
896   @param[in]  IpConfigData      Pointer to the EFI IPv4 Protocol configuration data structure.
897 
898   @retval EFI_SUCCESS           The driver instance was successfully opened.
899   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
900                                 RARP, etc.) is not finished yet.
901   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
902   @retval EFI_UNSUPPORTED       One or more of the following conditions is TRUE:
903                                 A configuration protocol (DHCP, BOOTP, RARP, etc.) could
904                                 not be located when clients choose to use the default IPv4
905                                 address. This EFI IPv4 Protocol implementation does not
906                                 support this requested filter or timeout setting.
907   @retval EFI_OUT_OF_RESOURCES  The EFI IPv4 Protocol driver instance data could not be allocated.
908   @retval EFI_ALREADY_STARTED   The interface is already open and must be stopped before the
909                                 IPv4 address or subnet mask can be changed. The interface must
910                                 also be stopped when switching to/from raw packet mode.
911   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred. The EFI IPv4
912                                 Protocol driver instance is not opened.
913 
914 **/
915 EFI_STATUS
916 EFIAPI
EfiIp4Configure(IN EFI_IP4_PROTOCOL * This,IN EFI_IP4_CONFIG_DATA * IpConfigData OPTIONAL)917 EfiIp4Configure (
918   IN EFI_IP4_PROTOCOL       *This,
919   IN EFI_IP4_CONFIG_DATA    *IpConfigData       OPTIONAL
920   )
921 {
922   IP4_PROTOCOL              *IpInstance;
923   EFI_IP4_CONFIG_DATA       *Current;
924   EFI_TPL                   OldTpl;
925   EFI_STATUS                Status;
926   BOOLEAN                   AddrOk;
927   IP4_ADDR                  IpAddress;
928   IP4_ADDR                  SubnetMask;
929 
930   //
931   // First, validate the parameters
932   //
933   if (This == NULL) {
934     return EFI_INVALID_PARAMETER;
935   }
936 
937   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
938   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
939 
940   //
941   // Validate the configuration first.
942   //
943   if (IpConfigData != NULL) {
944 
945     CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
946     CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
947 
948     IpAddress  = NTOHL (IpAddress);
949     SubnetMask = NTOHL (SubnetMask);
950 
951     //
952     // Check whether the station address is a valid unicast address
953     //
954     if (!IpConfigData->UseDefaultAddress) {
955       AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
956 
957       if (!AddrOk) {
958         Status = EFI_INVALID_PARAMETER;
959         goto ON_EXIT;
960       }
961     }
962 
963     //
964     // User can only update packet filters when already configured.
965     // If it wants to change the station address, it must configure(NULL)
966     // the instance first.
967     //
968     if (IpInstance->State == IP4_STATE_CONFIGED) {
969       Current = &IpInstance->ConfigData;
970 
971       if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
972         Status = EFI_ALREADY_STARTED;
973         goto ON_EXIT;
974       }
975 
976       if (!Current->UseDefaultAddress &&
977          (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
978           !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
979         Status = EFI_ALREADY_STARTED;
980         goto ON_EXIT;
981       }
982 
983       if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
984         Status = EFI_NO_MAPPING;
985         goto ON_EXIT;
986       }
987     }
988   }
989 
990   //
991   // Configure the instance or clean it up.
992   //
993   if (IpConfigData != NULL) {
994     Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
995   } else {
996     Status = Ip4CleanProtocol (IpInstance);
997 
998     //
999     // Don't change the state if it is DESTROY, consider the following
1000     // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
1001     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
1002     // the unload fails miserably.
1003     //
1004     if (IpInstance->State == IP4_STATE_CONFIGED) {
1005       IpInstance->State = IP4_STATE_UNCONFIGED;
1006     }
1007   }
1008 
1009   //
1010   // Update the MNP's configure data. Ip4ServiceConfigMnp will check
1011   // whether it is necessary to reconfigure the MNP.
1012   //
1013   Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
1014 
1015 ON_EXIT:
1016   gBS->RestoreTPL (OldTpl);
1017   return Status;
1018 
1019 }
1020 
1021 
1022 /**
1023   Change the IP4 child's multicast setting. The caller
1024   should make sure that the parameters is valid.
1025 
1026   @param[in]  IpInstance             The IP4 child to change the setting.
1027   @param[in]  JoinFlag               TRUE to join the group, otherwise leave it.
1028   @param[in]  GroupAddress           The target group address.
1029 
1030   @retval EFI_ALREADY_STARTED    Want to join the group, but already a member of it.
1031   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.
1032   @retval EFI_DEVICE_ERROR       Failed to set the group configuraton.
1033   @retval EFI_SUCCESS            Successfully updated the group setting.
1034   @retval EFI_NOT_FOUND          Try to leave the group which it isn't a member.
1035 
1036 **/
1037 EFI_STATUS
Ip4Groups(IN IP4_PROTOCOL * IpInstance,IN BOOLEAN JoinFlag,IN EFI_IPv4_ADDRESS * GroupAddress OPTIONAL)1038 Ip4Groups (
1039   IN IP4_PROTOCOL           *IpInstance,
1040   IN BOOLEAN                JoinFlag,
1041   IN EFI_IPv4_ADDRESS       *GroupAddress       OPTIONAL
1042   )
1043 {
1044   IP4_ADDR                  *Members;
1045   IP4_ADDR                  Group;
1046   UINT32                    Index;
1047 
1048   //
1049   // Add it to the instance's Groups, and join the group by IGMP.
1050   // IpInstance->Groups is in network byte order. IGMP operates in
1051   // host byte order
1052   //
1053   if (JoinFlag) {
1054     //
1055     // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.
1056     //
1057     ASSERT (GroupAddress != NULL);
1058     CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
1059 
1060     for (Index = 0; Index < IpInstance->GroupCount; Index++) {
1061       if (IpInstance->Groups[Index] == Group) {
1062         return EFI_ALREADY_STARTED;
1063       }
1064     }
1065 
1066     Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
1067 
1068     if (Members == NULL) {
1069       return EFI_OUT_OF_RESOURCES;
1070     }
1071 
1072     if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
1073       FreePool (Members);
1074       return EFI_DEVICE_ERROR;
1075     }
1076 
1077     if (IpInstance->Groups != NULL) {
1078       FreePool (IpInstance->Groups);
1079     }
1080 
1081     IpInstance->Groups = Members;
1082     IpInstance->GroupCount++;
1083 
1084     return EFI_SUCCESS;
1085   }
1086 
1087   //
1088   // Leave the group. Leave all the groups if GroupAddress is NULL.
1089   // Must iterate from the end to the beginning because the GroupCount
1090   // is decreamented each time an address is removed..
1091   //
1092   for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
1093     Group = IpInstance->Groups[Index - 1];
1094 
1095     if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
1096       if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
1097         return EFI_DEVICE_ERROR;
1098       }
1099 
1100       Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
1101       IpInstance->GroupCount--;
1102 
1103       if (IpInstance->GroupCount == 0) {
1104         ASSERT (Index == 1);
1105 
1106         FreePool (IpInstance->Groups);
1107         IpInstance->Groups = NULL;
1108       }
1109 
1110       if (GroupAddress != NULL) {
1111         return EFI_SUCCESS;
1112       }
1113     }
1114   }
1115 
1116   return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
1117 }
1118 
1119 
1120 /**
1121   Joins and leaves multicast groups.
1122 
1123   The Groups() function is used to join and leave multicast group sessions. Joining
1124   a group will enable reception of matching multicast packets. Leaving a group will
1125   disable the multicast packet reception.
1126 
1127   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
1128 
1129   @param[in]  This                  Pointer to the EFI_IP4_PROTOCOL instance.
1130   @param[in]  JoinFlag              Set to TRUE to join the multicast group session and FALSE to leave.
1131   @param[in]  GroupAddress          Pointer to the IPv4 multicast address.
1132 
1133   @retval EFI_SUCCESS           The operation completed successfully.
1134   @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
1135                                 - This is NULL.
1136                                 - JoinFlag is TRUE and GroupAddress is NULL.
1137                                 - GroupAddress is not NULL and *GroupAddress is
1138                                 not a multicast IPv4 address.
1139   @retval EFI_NOT_STARTED       This instance has not been started.
1140   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
1141                                 RARP, etc.) is not finished yet.
1142   @retval EFI_OUT_OF_RESOURCES  System resources could not be allocated.
1143   @retval EFI_UNSUPPORTED       This EFI IPv4 Protocol implementation does not support multicast groups.
1144   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when
1145                                 JoinFlag is TRUE).
1146   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is FALSE).
1147   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
1148 
1149 **/
1150 EFI_STATUS
1151 EFIAPI
EfiIp4Groups(IN EFI_IP4_PROTOCOL * This,IN BOOLEAN JoinFlag,IN EFI_IPv4_ADDRESS * GroupAddress OPTIONAL)1152 EfiIp4Groups (
1153   IN EFI_IP4_PROTOCOL       *This,
1154   IN BOOLEAN                JoinFlag,
1155   IN EFI_IPv4_ADDRESS       *GroupAddress     OPTIONAL
1156   )
1157 {
1158   IP4_PROTOCOL              *IpInstance;
1159   EFI_STATUS                Status;
1160   EFI_TPL                   OldTpl;
1161   IP4_ADDR                  McastIp;
1162 
1163   if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
1164     return EFI_INVALID_PARAMETER;
1165   }
1166 
1167   if (GroupAddress != NULL) {
1168     CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
1169 
1170     if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
1171       return EFI_INVALID_PARAMETER;
1172     }
1173   }
1174 
1175   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1176   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
1177 
1178   if (IpInstance->State != IP4_STATE_CONFIGED) {
1179     Status = EFI_NOT_STARTED;
1180     goto ON_EXIT;
1181   }
1182 
1183   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1184     Status = EFI_NO_MAPPING;
1185     goto ON_EXIT;
1186   }
1187 
1188   Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
1189 
1190 ON_EXIT:
1191   gBS->RestoreTPL (OldTpl);
1192   return Status;
1193 }
1194 
1195 
1196 /**
1197   Adds and deletes routing table entries.
1198 
1199   The Routes() function adds a route to or deletes a route from the routing table.
1200 
1201   Routes are determined by comparing the SubnetAddress with the destination IPv4
1202   address arithmetically AND-ed with the SubnetMask. The gateway address must be
1203   on the same subnet as the configured station address.
1204 
1205   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
1206   The default route matches all destination IPv4 addresses that do not match any
1207   other routes.
1208 
1209   A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
1210   IP address if it can be found in the ARP cache or on the local subnet. One automatic
1211   nonroute entry will be inserted into the routing table for outgoing packets that
1212   are addressed to a local subnet (gateway address of 0.0.0.0).
1213 
1214   Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
1215   IPv4 Protocol instances that use the default IPv4 address will also have copies
1216   of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
1217   copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
1218   instances. As a result, client modification to the routing table will be lost.
1219 
1220   @param[in]  This                   Pointer to the EFI_IP4_PROTOCOL instance.
1221   @param[in]  DeleteRoute            Set to TRUE to delete this route from the routing table. Set to
1222                                      FALSE to add this route to the routing table. SubnetAddress
1223                                      and SubnetMask are used as the key to each route entry.
1224   @param[in]  SubnetAddress          The address of the subnet that needs to be routed.
1225   @param[in]  SubnetMask             The subnet mask of SubnetAddress.
1226   @param[in]  GatewayAddress         The unicast gateway IPv4 address for this route.
1227 
1228   @retval EFI_SUCCESS            The operation completed successfully.
1229   @retval EFI_NOT_STARTED        The driver instance has not been started.
1230   @retval EFI_NO_MAPPING         When using the default address, configuration (DHCP, BOOTP,
1231                                  RARP, etc.) is not finished yet.
1232   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
1233                                  - This is NULL.
1234                                  - SubnetAddress is NULL.
1235                                  - SubnetMask is NULL.
1236                                  - GatewayAddress is NULL.
1237                                  - *SubnetAddress is not a valid subnet address.
1238                                  - *SubnetMask is not a valid subnet mask.
1239                                  - *GatewayAddress is not a valid unicast IPv4 address.
1240   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.
1241   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).
1242   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when
1243                                   DeleteRoute is FALSE).
1244 
1245 **/
1246 EFI_STATUS
1247 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)1248 EfiIp4Routes (
1249   IN EFI_IP4_PROTOCOL       *This,
1250   IN BOOLEAN                DeleteRoute,
1251   IN EFI_IPv4_ADDRESS       *SubnetAddress,
1252   IN EFI_IPv4_ADDRESS       *SubnetMask,
1253   IN EFI_IPv4_ADDRESS       *GatewayAddress
1254   )
1255 {
1256   IP4_PROTOCOL              *IpInstance;
1257   IP4_INTERFACE             *IpIf;
1258   IP4_ADDR                  Dest;
1259   IP4_ADDR                  Netmask;
1260   IP4_ADDR                  Nexthop;
1261   EFI_STATUS                Status;
1262   EFI_TPL                   OldTpl;
1263 
1264   //
1265   // First, validate the parameters
1266   //
1267   if ((This == NULL) || (SubnetAddress == NULL) ||
1268       (SubnetMask == NULL) || (GatewayAddress == NULL)) {
1269     return EFI_INVALID_PARAMETER;
1270   }
1271 
1272   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1273   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
1274 
1275   if (IpInstance->State != IP4_STATE_CONFIGED) {
1276     Status = EFI_NOT_STARTED;
1277     goto ON_EXIT;
1278   }
1279 
1280   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1281     Status = EFI_NO_MAPPING;
1282     goto ON_EXIT;
1283   }
1284 
1285   CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
1286   CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
1287   CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
1288 
1289   Dest    = NTOHL (Dest);
1290   Netmask = NTOHL (Netmask);
1291   Nexthop = NTOHL (Nexthop);
1292 
1293   IpIf    = IpInstance->Interface;
1294 
1295   if (!IP4_IS_VALID_NETMASK (Netmask)) {
1296     Status = EFI_INVALID_PARAMETER;
1297     goto ON_EXIT;
1298   }
1299 
1300   //
1301   // the gateway address must be a unicast on the connected network if not zero.
1302   //
1303   if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
1304       (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
1305         IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
1306 
1307     Status = EFI_INVALID_PARAMETER;
1308     goto ON_EXIT;
1309   }
1310 
1311   if (DeleteRoute) {
1312     Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1313   } else {
1314     Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1315   }
1316 
1317 ON_EXIT:
1318   gBS->RestoreTPL (OldTpl);
1319   return Status;
1320 }
1321 
1322 
1323 /**
1324   Check whether the user's token or event has already
1325   been enqueued on IP4's list.
1326 
1327   @param[in]  Map                    The container of either user's transmit or receive
1328                                      token.
1329   @param[in]  Item                   Current item to check against.
1330   @param[in]  Context                The Token to check againist.
1331 
1332   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP.
1333   @retval EFI_SUCCESS            The current item isn't the same token/event as the
1334                                  context.
1335 
1336 **/
1337 EFI_STATUS
1338 EFIAPI
Ip4TokenExist(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1339 Ip4TokenExist (
1340   IN NET_MAP                *Map,
1341   IN NET_MAP_ITEM           *Item,
1342   IN VOID                   *Context
1343   )
1344 {
1345   EFI_IP4_COMPLETION_TOKEN  *Token;
1346   EFI_IP4_COMPLETION_TOKEN  *TokenInItem;
1347 
1348   Token       = (EFI_IP4_COMPLETION_TOKEN *) Context;
1349   TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
1350 
1351   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
1352     return EFI_ACCESS_DENIED;
1353   }
1354 
1355   return EFI_SUCCESS;
1356 }
1357 
1358 /**
1359   Validate the user's token against current station address.
1360 
1361   @param[in]  Token              User's token to validate.
1362   @param[in]  IpIf               The IP4 child's interface.
1363   @param[in]  RawData            Set to TRUE to send unformatted packets.
1364 
1365   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
1366   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.
1367   @retval EFI_SUCCESS            The token is valid.
1368 
1369 **/
1370 EFI_STATUS
Ip4TxTokenValid(IN EFI_IP4_COMPLETION_TOKEN * Token,IN IP4_INTERFACE * IpIf,IN BOOLEAN RawData)1371 Ip4TxTokenValid (
1372   IN EFI_IP4_COMPLETION_TOKEN   *Token,
1373   IN IP4_INTERFACE              *IpIf,
1374   IN BOOLEAN                    RawData
1375   )
1376 {
1377   EFI_IP4_TRANSMIT_DATA     *TxData;
1378   EFI_IP4_OVERRIDE_DATA     *Override;
1379   IP4_ADDR                  Src;
1380   IP4_ADDR                  Gateway;
1381   UINT32                    Offset;
1382   UINT32                    Index;
1383   UINT32                    HeadLen;
1384 
1385   if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
1386     return EFI_INVALID_PARAMETER;
1387   }
1388 
1389   TxData = Token->Packet.TxData;
1390 
1391   //
1392   // Check the fragment table: no empty fragment, and length isn't bogus.
1393   //
1394   if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
1395     return EFI_INVALID_PARAMETER;
1396   }
1397 
1398   Offset = TxData->TotalDataLength;
1399 
1400   if (Offset > IP4_MAX_PACKET_SIZE) {
1401     return EFI_BAD_BUFFER_SIZE;
1402   }
1403 
1404   for (Index = 0; Index < TxData->FragmentCount; Index++) {
1405     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
1406         (TxData->FragmentTable[Index].FragmentLength == 0)) {
1407 
1408       return EFI_INVALID_PARAMETER;
1409     }
1410 
1411     Offset -= TxData->FragmentTable[Index].FragmentLength;
1412   }
1413 
1414   if (Offset != 0) {
1415     return EFI_INVALID_PARAMETER;
1416   }
1417 
1418   //
1419   // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData
1420   // is TRUE.
1421   //
1422   if (RawData) {
1423     return EFI_SUCCESS;
1424   }
1425 
1426   //
1427   // Check the IP options: no more than 40 bytes and format is OK
1428   //
1429   if (TxData->OptionsLength != 0) {
1430     if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
1431       return EFI_INVALID_PARAMETER;
1432     }
1433 
1434     if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
1435       return EFI_INVALID_PARAMETER;
1436     }
1437   }
1438 
1439   //
1440   // Check the source and gateway: they must be a valid unicast.
1441   // Gateway must also be on the connected network.
1442   //
1443   if (TxData->OverrideData != NULL) {
1444     Override = TxData->OverrideData;
1445 
1446     CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1447     CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
1448 
1449     Src     = NTOHL (Src);
1450     Gateway = NTOHL (Gateway);
1451 
1452     if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
1453         (Src == IP4_ALLONE_ADDRESS) ||
1454         IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
1455 
1456       return EFI_INVALID_PARAMETER;
1457     }
1458 
1459     //
1460     // If gateway isn't zero, it must be a unicast address, and
1461     // on the connected network.
1462     //
1463     if ((Gateway != IP4_ALLZERO_ADDRESS) &&
1464         ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
1465          !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
1466          IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
1467 
1468       return EFI_INVALID_PARAMETER;
1469     }
1470   }
1471 
1472   //
1473   // Check the packet length: Head length and packet length all has a limit
1474   //
1475   HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
1476 
1477   if ((HeadLen > IP4_MAX_HEADLEN) ||
1478       (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
1479 
1480     return EFI_BAD_BUFFER_SIZE;
1481   }
1482 
1483   return EFI_SUCCESS;
1484 }
1485 
1486 
1487 /**
1488   The callback function for the net buffer which wraps the user's
1489   transmit token. Although it seems this function is pretty simple,
1490   there are some subtle things.
1491   When user requests the IP to transmit a packet by passing it a
1492   token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
1493   is wrapped in an net buffer. the net buffer's Free function is
1494   set to Ip4FreeTxToken. The Token and token wrap are added to the
1495   IP child's TxToken map. Then the buffer is passed to Ip4Output for
1496   transmission. If something error happened before that, the buffer
1497   is freed, which in turn will free the token wrap. The wrap may
1498   have been added to the TxToken map or not, and the user's event
1499   shouldn't be fired because we are still in the EfiIp4Transmit. If
1500   the buffer has been sent by Ip4Output, it should be removed from
1501   the TxToken map and user's event signaled. The token wrap and buffer
1502   are bound together. Check the comments in Ip4Output for information
1503   about IP fragmentation.
1504 
1505   @param[in]  Context                The token's wrap.
1506 
1507 **/
1508 VOID
1509 EFIAPI
Ip4FreeTxToken(IN VOID * Context)1510 Ip4FreeTxToken (
1511   IN VOID                   *Context
1512   )
1513 {
1514   IP4_TXTOKEN_WRAP          *Wrap;
1515   NET_MAP_ITEM              *Item;
1516 
1517   Wrap = (IP4_TXTOKEN_WRAP *) Context;
1518 
1519   //
1520   // Signal IpSecRecycleEvent to inform IPsec free the memory
1521   //
1522   if (Wrap->IpSecRecycleSignal != NULL) {
1523     gBS->SignalEvent (Wrap->IpSecRecycleSignal);
1524   }
1525 
1526   //
1527   // Find the token in the instance's map. EfiIp4Transmit put the
1528   // token to the map. If that failed, NetMapFindKey will return NULL.
1529   //
1530   Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
1531 
1532   if (Item != NULL) {
1533     NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
1534   }
1535 
1536   if (Wrap->Sent) {
1537     gBS->SignalEvent (Wrap->Token->Event);
1538 
1539     //
1540     // Dispatch the DPC queued by the NotifyFunction of Token->Event.
1541     //
1542     DispatchDpc ();
1543   }
1544 
1545   FreePool (Wrap);
1546 }
1547 
1548 
1549 /**
1550   The callback function to Ip4Output to update the transmit status.
1551 
1552   @param  Ip4Instance            The Ip4Instance that request the transmit.
1553   @param  Packet                 The user's transmit request.
1554   @param  IoStatus               The result of the transmission.
1555   @param  Flag                   Not used during transmission.
1556   @param  Context                The token's wrap.
1557 
1558 **/
1559 VOID
Ip4OnPacketSent(IP4_PROTOCOL * Ip4Instance,NET_BUF * Packet,EFI_STATUS IoStatus,UINT32 Flag,VOID * Context)1560 Ip4OnPacketSent (
1561   IP4_PROTOCOL              *Ip4Instance,
1562   NET_BUF                   *Packet,
1563   EFI_STATUS                IoStatus,
1564   UINT32                    Flag,
1565   VOID                      *Context
1566   )
1567 {
1568   IP4_TXTOKEN_WRAP          *Wrap;
1569 
1570   //
1571   // This is the transmission request from upper layer,
1572   // not the IP4 driver itself.
1573   //
1574   ASSERT (Ip4Instance != NULL);
1575 
1576   //
1577   // The first fragment of the packet has been sent. Update
1578   // the token's status. That is, if fragmented, the transmit's
1579   // status is the first fragment's status. The Wrap will be
1580   // release when all the fragments are release. Check the comments
1581   // in Ip4FreeTxToken and Ip4Output for information.
1582   //
1583   Wrap                = (IP4_TXTOKEN_WRAP *) Context;
1584   Wrap->Token->Status = IoStatus;
1585 
1586   NetbufFree (Wrap->Packet);
1587 }
1588 
1589 
1590 /**
1591   Places outgoing data packets into the transmit queue.
1592 
1593   The Transmit() function places a sending request in the transmit queue of this
1594   EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
1595   errors occur, the event in the token will be signaled and the status is updated.
1596 
1597   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
1598   @param[in]  Token Pointer to the transmit token.
1599 
1600   @retval  EFI_SUCCESS           The data has been queued for transmission.
1601   @retval  EFI_NOT_STARTED       This instance has not been started.
1602   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
1603                                  RARP, etc.) is not finished yet.
1604   @retval  EFI_INVALID_PARAMETER One or more pameters are invalid.
1605   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.Event
1606                                  was already in the transmit queue.
1607   @retval  EFI_NOT_READY         The completion token could not be queued because the transmit
1608                                  queue is full.
1609   @retval  EFI_NOT_FOUND         Not route is found to destination address.
1610   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
1611   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too
1612                                  short to transmit.
1613   @retval  EFI_BAD_BUFFER_SIZE   The length of the IPv4 header + option length + total data length is
1614                                  greater than MTU (or greater than the maximum packet size if
1615                                  Token.Packet.TxData.OverrideData.
1616                                  DoNotFragment is TRUE).
1617 
1618 **/
1619 EFI_STATUS
1620 EFIAPI
EfiIp4Transmit(IN EFI_IP4_PROTOCOL * This,IN EFI_IP4_COMPLETION_TOKEN * Token)1621 EfiIp4Transmit (
1622   IN EFI_IP4_PROTOCOL         *This,
1623   IN EFI_IP4_COMPLETION_TOKEN *Token
1624   )
1625 {
1626   IP4_SERVICE               *IpSb;
1627   IP4_PROTOCOL              *IpInstance;
1628   IP4_INTERFACE             *IpIf;
1629   IP4_TXTOKEN_WRAP          *Wrap;
1630   EFI_IP4_TRANSMIT_DATA     *TxData;
1631   EFI_IP4_CONFIG_DATA       *Config;
1632   EFI_IP4_OVERRIDE_DATA     *Override;
1633   IP4_HEAD                  Head;
1634   IP4_ADDR                  GateWay;
1635   EFI_STATUS                Status;
1636   EFI_TPL                   OldTpl;
1637   BOOLEAN                   DontFragment;
1638   UINT32                    HeadLen;
1639   UINT8                     RawHdrLen;
1640   UINT32                    OptionsLength;
1641   UINT8                     *OptionsBuffer;
1642   VOID                      *FirstFragment;
1643 
1644   if (This == NULL) {
1645     return EFI_INVALID_PARAMETER;
1646   }
1647 
1648   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1649 
1650   if (IpInstance->State != IP4_STATE_CONFIGED) {
1651     return EFI_NOT_STARTED;
1652   }
1653 
1654   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
1655 
1656   IpSb    = IpInstance->Service;
1657   IpIf    = IpInstance->Interface;
1658   Config  = &IpInstance->ConfigData;
1659 
1660   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1661     Status = EFI_NO_MAPPING;
1662     goto ON_EXIT;
1663   }
1664 
1665   //
1666   // make sure that token is properly formated
1667   //
1668   Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);
1669 
1670   if (EFI_ERROR (Status)) {
1671     goto ON_EXIT;
1672   }
1673 
1674   //
1675   // Check whether the token or signal already existed.
1676   //
1677   if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
1678     Status = EFI_ACCESS_DENIED;
1679     goto ON_EXIT;
1680   }
1681 
1682   //
1683   // Build the IP header, need to fill in the Tos, TotalLen, Id,
1684   // fragment, Ttl, protocol, Src, and Dst.
1685   //
1686   TxData = Token->Packet.TxData;
1687 
1688   FirstFragment = NULL;
1689 
1690   if (Config->RawData) {
1691     //
1692     // When RawData is TRUE, first buffer in FragmentTable points to a raw
1693     // IPv4 fragment including IPv4 header and options.
1694     //
1695     FirstFragment = TxData->FragmentTable[0].FragmentBuffer;
1696     CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));
1697 
1698     RawHdrLen = (UINT8) (RawHdrLen & 0x0f);
1699     if (RawHdrLen < 5) {
1700       Status = EFI_INVALID_PARAMETER;
1701       goto ON_EXIT;
1702     }
1703 
1704     RawHdrLen = (UINT8) (RawHdrLen << 2);
1705 
1706     CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);
1707 
1708     Ip4NtohHead (&Head);
1709     HeadLen      = 0;
1710     DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);
1711 
1712     if (!DontFragment) {
1713       Status = EFI_INVALID_PARAMETER;
1714       goto ON_EXIT;
1715     }
1716 
1717     GateWay = IP4_ALLZERO_ADDRESS;
1718 
1719     //
1720     // Get IPv4 options from first fragment.
1721     //
1722     if (RawHdrLen == IP4_MIN_HEADLEN) {
1723       OptionsLength = 0;
1724       OptionsBuffer = NULL;
1725     } else {
1726       OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;
1727       OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;
1728     }
1729 
1730     //
1731     // Trim off IPv4 header and options from first fragment.
1732     //
1733     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;
1734     TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;
1735   } else {
1736     CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
1737     Head.Dst = NTOHL (Head.Dst);
1738 
1739     if (TxData->OverrideData != NULL) {
1740       Override      = TxData->OverrideData;
1741       Head.Protocol = Override->Protocol;
1742       Head.Tos      = Override->TypeOfService;
1743       Head.Ttl      = Override->TimeToLive;
1744       DontFragment  = Override->DoNotFragment;
1745 
1746       CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1747       CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
1748 
1749       Head.Src = NTOHL (Head.Src);
1750       GateWay  = NTOHL (GateWay);
1751     } else {
1752       Head.Src      = IpIf->Ip;
1753       GateWay       = IP4_ALLZERO_ADDRESS;
1754       Head.Protocol = Config->DefaultProtocol;
1755       Head.Tos      = Config->TypeOfService;
1756       Head.Ttl      = Config->TimeToLive;
1757       DontFragment  = Config->DoNotFragment;
1758     }
1759 
1760     Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
1761     HeadLen       = (TxData->OptionsLength + 3) & (~0x03);
1762 
1763     OptionsLength = TxData->OptionsLength;
1764     OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);
1765   }
1766 
1767   //
1768   // If don't fragment and fragment needed, return error
1769   //
1770   if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {
1771     Status = EFI_BAD_BUFFER_SIZE;
1772     goto ON_EXIT;
1773   }
1774 
1775   //
1776   // OK, it survives all the validation check. Wrap the token in
1777   // a IP4_TXTOKEN_WRAP and the data in a netbuf
1778   //
1779   Status = EFI_OUT_OF_RESOURCES;
1780   Wrap   = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));
1781   if (Wrap == NULL) {
1782     goto ON_EXIT;
1783   }
1784 
1785   Wrap->IpInstance  = IpInstance;
1786   Wrap->Token       = Token;
1787   Wrap->Sent        = FALSE;
1788   Wrap->Life        = IP4_US_TO_SEC (Config->TransmitTimeout);
1789   Wrap->Packet      = NetbufFromExt (
1790                         (NET_FRAGMENT *) TxData->FragmentTable,
1791                         TxData->FragmentCount,
1792                         IP4_MAX_HEADLEN,
1793                         0,
1794                         Ip4FreeTxToken,
1795                         Wrap
1796                         );
1797 
1798   if (Wrap->Packet == NULL) {
1799     FreePool (Wrap);
1800     goto ON_EXIT;
1801   }
1802 
1803   Token->Status = EFI_NOT_READY;
1804 
1805   if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
1806     //
1807     // NetbufFree will call Ip4FreeTxToken, which in turn will
1808     // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
1809     // enqueued.
1810     //
1811     if (Config->RawData) {
1812       //
1813       // Restore pointer of first fragment in RawData mode.
1814       //
1815       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1816     }
1817 
1818     NetbufFree (Wrap->Packet);
1819     goto ON_EXIT;
1820   }
1821 
1822   //
1823   // Mark the packet sent before output it. Mark it not sent again if the
1824   // returned status is not EFI_SUCCESS;
1825   //
1826   Wrap->Sent = TRUE;
1827 
1828   Status = Ip4Output (
1829              IpSb,
1830              IpInstance,
1831              Wrap->Packet,
1832              &Head,
1833              OptionsBuffer,
1834              OptionsLength,
1835              GateWay,
1836              Ip4OnPacketSent,
1837              Wrap
1838              );
1839 
1840   if (EFI_ERROR (Status)) {
1841     Wrap->Sent = FALSE;
1842 
1843     if (Config->RawData) {
1844       //
1845       // Restore pointer of first fragment in RawData mode.
1846       //
1847       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1848     }
1849 
1850     NetbufFree (Wrap->Packet);
1851   }
1852 
1853   if (Config->RawData) {
1854     //
1855     // Restore pointer of first fragment in RawData mode.
1856     //
1857     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1858   }
1859 
1860 ON_EXIT:
1861   gBS->RestoreTPL (OldTpl);
1862   return Status;
1863 }
1864 
1865 
1866 /**
1867   Places a receiving request into the receiving queue.
1868 
1869   The Receive() function places a completion token into the receive packet queue.
1870   This function is always asynchronous.
1871 
1872   The Token.Event field in the completion token must be filled in by the caller
1873   and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
1874   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
1875   is signaled.
1876 
1877   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
1878   @param[in]  Token Pointer to a token that is associated with the receive data descriptor.
1879 
1880   @retval EFI_SUCCESS           The receive completion token was cached.
1881   @retval EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
1882   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
1883                                 is not finished yet.
1884   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
1885                                 - This is NULL.
1886                                 - Token is NULL.
1887                                 - Token.Event is NULL.
1888   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system
1889                                 resources (usually memory).
1890   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
1891                                 The EFI IPv4 Protocol instance has been reset to startup defaults.
1892                                 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
1893                                 in the receive queue.
1894   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.
1895   @retval EFI_ICMP_ERROR        An ICMP error packet was received.
1896 
1897 **/
1898 EFI_STATUS
1899 EFIAPI
EfiIp4Receive(IN EFI_IP4_PROTOCOL * This,IN EFI_IP4_COMPLETION_TOKEN * Token)1900 EfiIp4Receive (
1901   IN EFI_IP4_PROTOCOL         *This,
1902   IN EFI_IP4_COMPLETION_TOKEN *Token
1903   )
1904 {
1905   IP4_PROTOCOL              *IpInstance;
1906   EFI_STATUS                Status;
1907   EFI_TPL                   OldTpl;
1908 
1909   //
1910   // First validate the parameters
1911   //
1912   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
1913     return EFI_INVALID_PARAMETER;
1914   }
1915 
1916   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1917 
1918   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1919 
1920   if (IpInstance->State != IP4_STATE_CONFIGED) {
1921     Status = EFI_NOT_STARTED;
1922     goto ON_EXIT;
1923   }
1924 
1925   //
1926   // Check whether the toke is already on the receive queue.
1927   //
1928   Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
1929 
1930   if (EFI_ERROR (Status)) {
1931     Status = EFI_ACCESS_DENIED;
1932     goto ON_EXIT;
1933   }
1934 
1935   //
1936   // Queue the token then check whether there is pending received packet.
1937   //
1938   Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
1939 
1940   if (EFI_ERROR (Status)) {
1941     goto ON_EXIT;
1942   }
1943 
1944   Status = Ip4InstanceDeliverPacket (IpInstance);
1945 
1946   //
1947   // Dispatch the DPC queued by the NotifyFunction of this instane's receive
1948   // event.
1949   //
1950   DispatchDpc ();
1951 
1952 ON_EXIT:
1953   gBS->RestoreTPL (OldTpl);
1954   return Status;
1955 }
1956 
1957 
1958 /**
1959   Cancel the transmitted but not recycled packet. If a matching
1960   token is found, it will call Ip4CancelPacket to cancel the
1961   packet. Ip4CancelPacket will cancel all the fragments of the
1962   packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
1963   will be deleted from the Map, and user's event signalled.
1964   Because Ip4CancelPacket and other functions are all called in
1965   line, so, after Ip4CancelPacket returns, the Item has been freed.
1966 
1967   @param[in]  Map                The IP4 child's transmit queue.
1968   @param[in]  Item               The current transmitted packet to test.
1969   @param[in]  Context            The user's token to cancel.
1970 
1971   @retval EFI_SUCCESS            Continue to check the next Item.
1972   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.
1973 
1974 **/
1975 EFI_STATUS
1976 EFIAPI
Ip4CancelTxTokens(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1977 Ip4CancelTxTokens (
1978   IN NET_MAP                *Map,
1979   IN NET_MAP_ITEM           *Item,
1980   IN VOID                   *Context
1981   )
1982 {
1983   EFI_IP4_COMPLETION_TOKEN  *Token;
1984   IP4_TXTOKEN_WRAP          *Wrap;
1985 
1986   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1987 
1988   //
1989   // Return EFI_SUCCESS to check the next item in the map if
1990   // this one doesn't match.
1991   //
1992   if ((Token != NULL) && (Token != Item->Key)) {
1993     return EFI_SUCCESS;
1994   }
1995 
1996   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
1997   ASSERT (Wrap != NULL);
1998 
1999   //
2000   // Don't access the Item, Wrap and Token's members after this point.
2001   // Item and wrap has been freed. And we no longer own the Token.
2002   //
2003   Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
2004 
2005   //
2006   // If only one item is to be cancel, return EFI_ABORTED to stop
2007   // iterating the map any more.
2008   //
2009   if (Token != NULL) {
2010     return EFI_ABORTED;
2011   }
2012 
2013   return EFI_SUCCESS;
2014 }
2015 
2016 
2017 /**
2018   Cancel the receive request. This is quiet simple, because
2019   it is only enqueued in our local receive map.
2020 
2021   @param[in]  Map                The IP4 child's receive queue.
2022   @param[in]  Item               Current receive request to cancel.
2023   @param[in]  Context            The user's token to cancel.
2024 
2025   @retval EFI_SUCCESS            Continue to check the next receive request on the
2026                                  queue.
2027   @retval EFI_ABORTED            The user's token (token != NULL) has been
2028                                  cancelled.
2029 
2030 **/
2031 EFI_STATUS
2032 EFIAPI
Ip4CancelRxTokens(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)2033 Ip4CancelRxTokens (
2034   IN NET_MAP                *Map,
2035   IN NET_MAP_ITEM           *Item,
2036   IN VOID                   *Context
2037   )
2038 {
2039   EFI_IP4_COMPLETION_TOKEN  *Token;
2040   EFI_IP4_COMPLETION_TOKEN  *This;
2041 
2042   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
2043   This  = Item->Key;
2044 
2045   if ((Token != NULL) && (Token != This)) {
2046     return EFI_SUCCESS;
2047   }
2048 
2049   NetMapRemoveItem (Map, Item, NULL);
2050 
2051   This->Status        = EFI_ABORTED;
2052   This->Packet.RxData = NULL;
2053   gBS->SignalEvent (This->Event);
2054 
2055   if (Token != NULL) {
2056     return EFI_ABORTED;
2057   }
2058 
2059   return EFI_SUCCESS;
2060 }
2061 
2062 
2063 /**
2064   Cancel the user's receive/transmit request.
2065 
2066   @param[in]  IpInstance         The IP4 child.
2067   @param[in]  Token              The token to cancel. If NULL, all token will be
2068                                  cancelled.
2069 
2070   @retval EFI_SUCCESS            The token is cancelled.
2071   @retval EFI_NOT_FOUND          The token isn't found on either the
2072                                  transmit/receive queue.
2073   @retval EFI_DEVICE_ERROR       Not all token is cancelled when Token is NULL.
2074 
2075 **/
2076 EFI_STATUS
Ip4Cancel(IN IP4_PROTOCOL * IpInstance,IN EFI_IP4_COMPLETION_TOKEN * Token OPTIONAL)2077 Ip4Cancel (
2078   IN IP4_PROTOCOL             *IpInstance,
2079   IN EFI_IP4_COMPLETION_TOKEN *Token          OPTIONAL
2080   )
2081 {
2082   EFI_STATUS                Status;
2083 
2084   //
2085   // First check the transmitted packet. Ip4CancelTxTokens returns
2086   // EFI_ABORTED to mean that the token has been cancelled when
2087   // token != NULL. So, return EFI_SUCCESS for this condition.
2088   //
2089   Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
2090 
2091   if (EFI_ERROR (Status)) {
2092     if ((Token != NULL) && (Status == EFI_ABORTED)) {
2093       return EFI_SUCCESS;
2094     }
2095 
2096     return Status;
2097   }
2098 
2099   //
2100   // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
2101   // for Token!=NULL and it is cancelled.
2102   //
2103   Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
2104   //
2105   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
2106   // events.
2107   //
2108   DispatchDpc ();
2109   if (EFI_ERROR (Status)) {
2110     if ((Token != NULL) && (Status == EFI_ABORTED)) {
2111       return EFI_SUCCESS;
2112     }
2113 
2114     return Status;
2115   }
2116 
2117   //
2118   // OK, if the Token is found when Token != NULL, the NetMapIterate
2119   // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
2120   //
2121   if (Token != NULL) {
2122     return EFI_NOT_FOUND;
2123   }
2124 
2125   //
2126   // If Token == NULL, cancel all the tokens. return error if no
2127   // all of them are cancelled.
2128   //
2129   if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
2130       !NetMapIsEmpty (&IpInstance->RxTokens)) {
2131 
2132     return EFI_DEVICE_ERROR;
2133   }
2134 
2135   return EFI_SUCCESS;
2136 }
2137 
2138 
2139 /**
2140   Abort an asynchronous transmit or receive request.
2141 
2142   The Cancel() function is used to abort a pending transmit or receive request.
2143   If the token is in the transmit or receive request queues, after calling this
2144   function, Token->Status will be set to EFI_ABORTED and then Token->Event will
2145   be signaled. If the token is not in one of the queues, which usually means the
2146   asynchronous operation has completed, this function will not signal the token
2147   and EFI_NOT_FOUND is returned.
2148 
2149   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
2150   @param[in]  Token Pointer to a token that has been issued by
2151                     EFI_IP4_PROTOCOL.Transmit() or
2152                     EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
2153                     tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
2154                     defined in EFI_IP4_PROTOCOL.Transmit().
2155 
2156   @retval EFI_SUCCESS           The asynchronous I/O request was aborted and
2157                                 Token.->Event was signaled. When Token is NULL, all
2158                                 pending requests were aborted and their events were signaled.
2159   @retval EFI_INVALID_PARAMETER This is NULL.
2160   @retval EFI_NOT_STARTED       This instance has not been started.
2161   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
2162                                 RARP, etc.) is not finished yet.
2163   @retval EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was
2164                                 not found in the transmit or receive queue. It has either completed
2165                                 or was not issued by Transmit() and Receive().
2166 
2167 **/
2168 EFI_STATUS
2169 EFIAPI
EfiIp4Cancel(IN EFI_IP4_PROTOCOL * This,IN EFI_IP4_COMPLETION_TOKEN * Token OPTIONAL)2170 EfiIp4Cancel (
2171   IN EFI_IP4_PROTOCOL         *This,
2172   IN EFI_IP4_COMPLETION_TOKEN *Token    OPTIONAL
2173   )
2174 {
2175   IP4_PROTOCOL              *IpInstance;
2176   EFI_STATUS                Status;
2177   EFI_TPL                   OldTpl;
2178 
2179   if (This == NULL) {
2180     return EFI_INVALID_PARAMETER;
2181   }
2182 
2183   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
2184 
2185   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2186 
2187   if (IpInstance->State != IP4_STATE_CONFIGED) {
2188     Status = EFI_NOT_STARTED;
2189     goto ON_EXIT;
2190   }
2191 
2192   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
2193     Status = EFI_NO_MAPPING;
2194     goto ON_EXIT;
2195   }
2196 
2197   Status = Ip4Cancel (IpInstance, Token);
2198 
2199 ON_EXIT:
2200   gBS->RestoreTPL (OldTpl);
2201   return Status;
2202 }
2203 
2204 
2205 /**
2206   Polls for incoming data packets and processes outgoing data packets.
2207 
2208   The Poll() function polls for incoming data packets and processes outgoing data
2209   packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
2210   function to increase the rate that data packets are moved between the communications
2211   device and the transmit and receive queues.
2212 
2213   In some systems the periodic timer event may not poll the underlying communications
2214   device fast enough to transmit and/or receive all data packets without missing
2215   incoming packets or dropping outgoing packets. Drivers and applications that are
2216   experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
2217   more often.
2218 
2219   @param[in]  This               Pointer to the EFI_IP4_PROTOCOL instance.
2220 
2221   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.
2222   @retval  EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
2223   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
2224                                  RARP, etc.) is not finished yet.
2225   @retval  EFI_INVALID_PARAMETER This is NULL.
2226   @retval  EFI_DEVICE_ERROR      An unexpected system or network error occurred.
2227   @retval  EFI_NOT_READY         No incoming or outgoing data is processed.
2228   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
2229                                  Consider increasing the polling rate.
2230 
2231 **/
2232 EFI_STATUS
2233 EFIAPI
EfiIp4Poll(IN EFI_IP4_PROTOCOL * This)2234 EfiIp4Poll (
2235   IN EFI_IP4_PROTOCOL       *This
2236   )
2237 {
2238   IP4_PROTOCOL                  *IpInstance;
2239   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
2240 
2241   if (This == NULL) {
2242     return EFI_INVALID_PARAMETER;
2243   }
2244 
2245   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
2246 
2247   if (IpInstance->State == IP4_STATE_UNCONFIGED) {
2248     return EFI_NOT_STARTED;
2249   }
2250 
2251   Mnp = IpInstance->Service->Mnp;
2252 
2253   //
2254   // Don't lock the Poll function to enable the deliver of
2255   // the packet polled up.
2256   //
2257   return Mnp->Poll (Mnp);
2258 }
2259 
2260 /**
2261   Decrease the life of the transmitted packets. If it is
2262   decreased to zero, cancel the packet. This function is
2263   called by Ip4PacketTimerTicking which time out both the
2264   received-but-not-delivered and transmitted-but-not-recycle
2265   packets.
2266 
2267   @param[in]  Map                    The IP4 child's transmit map.
2268   @param[in]  Item                   Current transmitted packet.
2269   @param[in]  Context                Not used.
2270 
2271   @retval EFI_SUCCESS            Always returns EFI_SUCCESS.
2272 
2273 **/
2274 EFI_STATUS
2275 EFIAPI
Ip4SentPacketTicking(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)2276 Ip4SentPacketTicking (
2277   IN NET_MAP                *Map,
2278   IN NET_MAP_ITEM           *Item,
2279   IN VOID                   *Context
2280   )
2281 {
2282   IP4_TXTOKEN_WRAP          *Wrap;
2283 
2284   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
2285   ASSERT (Wrap != NULL);
2286 
2287   if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
2288     Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
2289   }
2290 
2291   return EFI_SUCCESS;
2292 }
2293 
2294 
2295 /**
2296   There are two steps for this the heart beat timer of IP4 service instance.
2297   First, it times out all of its IP4 children's received-but-not-delivered
2298   and transmitted-but-not-recycle packets, and provides time input for its
2299   IGMP protocol.
2300   Second, a dedicated timer is used to poll underlying media status. In case
2301   of cable swap, a new round auto configuration will be initiated. The timer
2302   will signal the IP4 to run DHCP configuration again. IP4 driver will free
2303   old IP address related resource, such as route table and Interface, then
2304   initiate a DHCP process to acquire new IP, eventually create route table
2305   for new IP address.
2306 
2307   @param[in]  Event                  The IP4 service instance's heart beat timer.
2308   @param[in]  Context                The IP4 service instance.
2309 
2310 **/
2311 VOID
2312 EFIAPI
Ip4TimerTicking(IN EFI_EVENT Event,IN VOID * Context)2313 Ip4TimerTicking (
2314   IN EFI_EVENT              Event,
2315   IN VOID                   *Context
2316   )
2317 {
2318   IP4_SERVICE               *IpSb;
2319   BOOLEAN                   OldMediaPresent;
2320   EFI_STATUS                Status;
2321   EFI_SIMPLE_NETWORK_MODE   SnpModeData;
2322 
2323   IpSb = (IP4_SERVICE *) Context;
2324   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
2325 
2326   OldMediaPresent = IpSb->MediaPresent;
2327 
2328   Ip4PacketTimerTicking (IpSb);
2329   Ip4IgmpTicking (IpSb);
2330 
2331   //
2332   // Get fresh mode data from MNP, since underlying media status may change.
2333   // Here, it needs to mention that the MediaPresent can also be checked even if
2334   // EFI_NOT_STARTED returned while this MNP child driver instance isn't configured.
2335   //
2336   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &SnpModeData);
2337   if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
2338     return;
2339   }
2340 
2341   IpSb->MediaPresent = SnpModeData.MediaPresent;
2342   //
2343   // Media transimit Unpresent to Present means new link movement is detected.
2344   //
2345   if (!OldMediaPresent && IpSb->MediaPresent && (IpSb->Ip4Config2Instance.Policy == Ip4Config2PolicyDhcp)) {
2346     //
2347     // Signal the IP4 to run the dhcp configuration again. IP4 driver will free
2348     // old IP address related resource, such as route table and Interface, then
2349     // initiate a DHCP round to acquire new IP, eventually
2350     // create route table for new IP address.
2351     //
2352     if (IpSb->ReconfigEvent != NULL) {
2353       Status = gBS->SignalEvent (IpSb->ReconfigEvent);
2354       DispatchDpc ();
2355     }
2356   }
2357 }
2358