Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Impl.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 \r
13 Module Name:\r
14 \r
15   Ip4Impl.c\r
16 \r
17 Abstract:\r
18 \r
19 \r
20 **/\r
21 \r
22 #include "Ip4Impl.h"\r
23 \r
24 \r
25 /**\r
26   Get the IP child's current operational data. This can\r
27   all be used to get the underlying MNP and SNP data.\r
28 \r
29   @param  This                   The IP4 protocol instance\r
30   @param  Ip4ModeData            The IP4 operation data\r
31   @param  MnpConfigData          The MNP configure data\r
32   @param  SnpModeData            The SNP operation data\r
33 \r
34   @retval EFI_INVALID_PARAMETER  The parameter is invalid because This == NULL\r
35   @retval EFI_SUCCESS            The operational parameter is returned.\r
36   @retval Others                 Failed to retrieve the IP4 route table.\r
37 \r
38 **/\r
39 EFI_STATUS\r
40 EFIAPI\r
41 EfiIp4GetModeData (\r
42   IN  CONST EFI_IP4_PROTOCOL                *This,\r
43   OUT       EFI_IP4_MODE_DATA               *Ip4ModeData,    OPTIONAL\r
44   OUT       EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData,  OPTIONAL\r
45   OUT       EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL\r
46   )\r
47 {\r
48   IP4_PROTOCOL              *IpInstance;\r
49   IP4_SERVICE               *IpSb;\r
50   EFI_IP4_CONFIG_DATA       *Config;\r
51   EFI_STATUS                Status;\r
52   EFI_TPL                   OldTpl;\r
53   IP4_ADDR                  Ip;\r
54 \r
55   if (This == NULL) {\r
56     return EFI_INVALID_PARAMETER;\r
57   }\r
58 \r
59   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
60   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
61   IpSb       = IpInstance->Service;\r
62 \r
63   if (Ip4ModeData != NULL) {\r
64     //\r
65     // IsStarted is "whether the EfiIp4Configure has been called".\r
66     // IsConfigured is "whether the station address has been configured"\r
67     //\r
68     Ip4ModeData->IsStarted     = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);\r
69     CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));\r
70     Ip4ModeData->IsConfigured  = FALSE;\r
71 \r
72     Ip4ModeData->GroupCount    = IpInstance->GroupCount;\r
73     Ip4ModeData->GroupTable    = (EFI_IPv4_ADDRESS *) IpInstance->Groups;\r
74 \r
75     Ip4ModeData->IcmpTypeCount = 23;\r
76     Ip4ModeData->IcmpTypeList  = mIp4SupportedIcmp;\r
77 \r
78     Ip4ModeData->RouteTable    = NULL;\r
79     Ip4ModeData->RouteCount    = 0;\r
80 \r
81     //\r
82     // return the current station address for this IP child. So,\r
83     // the user can get the default address through this. Some\r
84     // application wants to know it station address even it is\r
85     // using the default one, such as a ftp server.\r
86     //\r
87     if (Ip4ModeData->IsStarted) {\r
88       Config  = &Ip4ModeData->ConfigData;\r
89 \r
90       Ip = HTONL (IpInstance->Interface->Ip);\r
91       CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
92 \r
93       Ip = HTONL (IpInstance->Interface->SubnetMask);\r
94       CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
95 \r
96       Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;\r
97 \r
98       //\r
99       // Build a EFI route table for user from the internal route table.\r
100       //\r
101       Status = Ip4BuildEfiRouteTable (IpInstance);\r
102 \r
103       if (EFI_ERROR (Status)) {\r
104         gBS->RestoreTPL (OldTpl);\r
105         return Status;\r
106       }\r
107 \r
108       Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;\r
109       Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;\r
110     }\r
111   }\r
112 \r
113   if (MnpConfigData != NULL) {\r
114     CopyMem (MnpConfigData, &IpSb->MnpConfigData, sizeof (*MnpConfigData));\r
115   }\r
116 \r
117   if (SnpModeData != NULL) {\r
118     CopyMem (SnpModeData, &IpSb->SnpMode, sizeof (*SnpModeData));\r
119   }\r
120 \r
121   gBS->RestoreTPL (OldTpl);\r
122   return EFI_SUCCESS;\r
123 }\r
124 \r
125 \r
126 /**\r
127   Config the MNP parameter used by IP. The IP driver use one MNP\r
128   child to transmit/receive frames. By default, it configures MNP\r
129   to receive unicast/multicast/broadcast. And it will enable/disable\r
130   the promiscous receive according to whether there is IP child\r
131   enable that or not. If Force isn't false, it will iterate through\r
132   all the IP children to check whether the promiscuous receive\r
133   setting has been changed. If it hasn't been changed, it won't\r
134   reconfigure the MNP. If Force is true, the MNP is configured no\r
135   matter whether that is changed or not.\r
136 \r
137   @param  IpSb                   The IP4 service instance that is to be changed.\r
138   @param  Force                  Force the configuration or not.\r
139 \r
140   @retval EFI_SUCCESS            The MNP is successfully configured/reconfigured.\r
141   @retval Others                 Configuration failed.\r
142 \r
143 **/\r
144 EFI_STATUS\r
145 Ip4ServiceConfigMnp (\r
146   IN IP4_SERVICE            *IpSb,\r
147   IN BOOLEAN                Force\r
148   )\r
149 {\r
150   LIST_ENTRY                *Entry;\r
151   LIST_ENTRY                *ProtoEntry;\r
152   IP4_INTERFACE             *IpIf;\r
153   IP4_PROTOCOL              *IpInstance;\r
154   BOOLEAN                   Reconfig;\r
155   BOOLEAN                   PromiscReceive;\r
156   EFI_STATUS                Status;\r
157 \r
158   Reconfig       = FALSE;\r
159   PromiscReceive = FALSE;\r
160 \r
161   if (!Force) {\r
162     //\r
163     // Iterate through the IP children to check whether promiscuous\r
164     // receive setting has been changed. Update the interface's receive\r
165     // filter also.\r
166     //\r
167     NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
168 \r
169       IpIf              = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
170       IpIf->PromiscRecv = FALSE;\r
171 \r
172       NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {\r
173         IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);\r
174 \r
175         if (IpInstance->ConfigData.AcceptPromiscuous) {\r
176           IpIf->PromiscRecv = TRUE;\r
177           PromiscReceive    = TRUE;\r
178         }\r
179       }\r
180     }\r
181 \r
182     //\r
183     // If promiscuous receive isn't changed, it isn't necessary to reconfigure.\r
184     //\r
185     if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
186       return EFI_SUCCESS;\r
187     }\r
188 \r
189     Reconfig  = TRUE;\r
190     IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;\r
191   }\r
192 \r
193   Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);\r
194 \r
195   //\r
196   // recover the original configuration if failed to set the configure.\r
197   //\r
198   if (EFI_ERROR (Status) && Reconfig) {\r
199     IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;\r
200   }\r
201 \r
202   return Status;\r
203 }\r
204 \r
205 \r
206 /**\r
207   The event handle for IP4 auto configuration. If IP is asked\r
208   to reconfigure the default address. The original default\r
209   interface and route table are removed as the default. If there\r
210   is active IP children using the default address, the interface\r
211   will remain valid until all the children have freed their\r
212   references. If IP is signalled when auto configuration is done,\r
213   it will configure the default interface and default route table\r
214   with the configuration information retrieved by IP4_CONFIGURE.\r
215 \r
216   @param  Context                The IP4 service binding instance.\r
217 \r
218   @return None\r
219 \r
220 **/\r
221 VOID\r
222 EFIAPI\r
223 Ip4AutoConfigCallBackDpc (\r
224   IN VOID                   *Context\r
225   )\r
226 {\r
227   EFI_IP4_CONFIG_PROTOCOL   *Ip4Config;\r
228   EFI_IP4_IPCONFIG_DATA     *Data;\r
229   EFI_IP4_ROUTE_TABLE       *RouteEntry;\r
230   IP4_SERVICE               *IpSb;\r
231   IP4_ROUTE_TABLE           *RouteTable;\r
232   IP4_INTERFACE             *IpIf;\r
233   EFI_STATUS                Status;\r
234   UINTN                     Len;\r
235   UINT32                    Index;\r
236 \r
237   IpSb      = (IP4_SERVICE *) Context;\r
238   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
239 \r
240   Ip4Config = IpSb->Ip4Config;\r
241 \r
242   //\r
243   // IP is asked to do the reconfiguration. If the default interface\r
244   // has been configured, release the default interface and route\r
245   // table, then create a new one. If there are some IP children\r
246   // using it, the interface won't be physically freed until all the\r
247   // children have released their reference to it. Also remember to\r
248   // restart the receive on the default address. IP4 driver only receive\r
249   // frames on the default address, and when the default interface is\r
250   // freed, Ip4AcceptFrame won't be informed.\r
251   //\r
252   if (IpSb->ActiveEvent == IpSb->ReconfigEvent) {\r
253 \r
254     if (IpSb->DefaultInterface->Configured) {\r
255       IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
256 \r
257       if (IpIf == NULL) {\r
258         return;\r
259       }\r
260 \r
261       RouteTable = Ip4CreateRouteTable ();\r
262 \r
263       if (RouteTable == NULL) {\r
264         Ip4FreeInterface (IpIf, NULL);\r
265         return;\r
266       }\r
267 \r
268       Ip4CancelReceive (IpSb->DefaultInterface);\r
269       Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
270       Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
271 \r
272       IpSb->DefaultInterface  = IpIf;\r
273       InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
274 \r
275       IpSb->DefaultRouteTable = RouteTable;\r
276       Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
277     }\r
278 \r
279     Ip4Config->Stop (Ip4Config);\r
280     Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);\r
281     return ;\r
282   }\r
283 \r
284   //\r
285   // Get the configure data in two steps: get the length then the data.\r
286   //\r
287   Len = 0;\r
288 \r
289   if (Ip4Config->GetData (Ip4Config, &Len, NULL) != EFI_BUFFER_TOO_SMALL) {\r
290     return ;\r
291   }\r
292 \r
293   Data = AllocatePool (Len);\r
294 \r
295   if (Data == NULL) {\r
296     return ;\r
297   }\r
298 \r
299   Status = Ip4Config->GetData (Ip4Config, &Len, Data);\r
300 \r
301   if (EFI_ERROR (Status)) {\r
302     goto ON_EXIT;\r
303   }\r
304 \r
305   IpIf = IpSb->DefaultInterface;\r
306 \r
307   //\r
308   // If the default address has been configured don't change it.\r
309   // This is unlikely to happen if EFI_IP4_CONFIG protocol has\r
310   // informed us to reconfigure each time it wants to change the\r
311   // configuration parameters.\r
312   //\r
313   if (IpIf->Configured) {\r
314     goto ON_EXIT;\r
315   }\r
316 \r
317   //\r
318   // Set the default interface's address, then add a directed\r
319   // route for it, that is, the route whose nexthop is zero.\r
320   //\r
321   Status = Ip4SetAddress (\r
322              IpIf,\r
323              EFI_NTOHL (Data->StationAddress),\r
324              EFI_NTOHL (Data->SubnetMask)\r
325              );\r
326 \r
327   if (EFI_ERROR (Status)) {\r
328     goto ON_EXIT;\r
329   }\r
330 \r
331   Ip4AddRoute (\r
332     IpSb->DefaultRouteTable,\r
333     EFI_NTOHL (Data->StationAddress),\r
334     EFI_NTOHL (Data->SubnetMask),\r
335     IP4_ALLZERO_ADDRESS\r
336     );\r
337 \r
338   //\r
339   // Add routes returned by EFI_IP4_CONFIG protocol.\r
340   //\r
341   for (Index = 0; Index < Data->RouteTableSize; Index++) {\r
342     RouteEntry = &Data->RouteTable[Index];\r
343 \r
344     Ip4AddRoute (\r
345       IpSb->DefaultRouteTable,\r
346       EFI_NTOHL (RouteEntry->SubnetAddress),\r
347       EFI_NTOHL (RouteEntry->SubnetMask),\r
348       EFI_NTOHL (RouteEntry->GatewayAddress)\r
349       );\r
350   }\r
351 \r
352   IpSb->State = IP4_SERVICE_CONFIGED;\r
353 \r
354   Ip4SetVariableData (IpSb);\r
355 \r
356 ON_EXIT:\r
357   gBS->FreePool (Data);\r
358 }\r
359 \r
360 VOID\r
361 EFIAPI\r
362 Ip4AutoConfigCallBack (\r
363   IN EFI_EVENT              Event,\r
364   IN VOID                   *Context\r
365   )\r
366 /*++\r
367 \r
368 Routine Description:\r
369 \r
370   Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK\r
371 \r
372 Arguments:\r
373 \r
374   Event   - The event that is signalled.\r
375   Context - The IP4 service binding instance.\r
376 \r
377 Returns:\r
378 \r
379   None\r
380 \r
381 --*/\r
382 {\r
383   IP4_SERVICE  *IpSb;\r
384 \r
385   IpSb              = (IP4_SERVICE *) Context;\r
386   IpSb->ActiveEvent = Event;\r
387 \r
388   //\r
389   // Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK\r
390   //\r
391   NetLibQueueDpc (TPL_CALLBACK, Ip4AutoConfigCallBackDpc, Context);\r
392 }\r
393 \r
394 \r
395 /**\r
396   Start the auto configuration for this IP service instance.\r
397   It will locates the EFI_IP4_CONFIG_PROTOCOL, then start the\r
398   auto configuration.\r
399 \r
400   @param  IpSb                   The IP4 service instance to configure\r
401 \r
402   @retval EFI_SUCCESS            The auto configuration is successfull started\r
403   @retval Others                 Failed to start auto configuration.\r
404 \r
405 **/\r
406 EFI_STATUS\r
407 Ip4StartAutoConfig (\r
408   IN IP4_SERVICE            *IpSb\r
409   )\r
410 {\r
411   EFI_IP4_CONFIG_PROTOCOL   *Ip4Config;\r
412   EFI_STATUS                Status;\r
413 \r
414   if (IpSb->State > IP4_SERVICE_UNSTARTED) {\r
415     return EFI_SUCCESS;\r
416   }\r
417 \r
418   //\r
419   // Create the DoneEvent and ReconfigEvent to call EFI_IP4_CONFIG\r
420   //\r
421   Status = gBS->CreateEvent (\r
422                   EVT_NOTIFY_SIGNAL,\r
423                   TPL_CALLBACK,\r
424                   Ip4AutoConfigCallBack,\r
425                   IpSb,\r
426                   &IpSb->DoneEvent\r
427                   );\r
428 \r
429   if (EFI_ERROR (Status)) {\r
430     return Status;\r
431   }\r
432 \r
433   Status = gBS->CreateEvent (\r
434                   EVT_NOTIFY_SIGNAL,\r
435                   TPL_NOTIFY,\r
436                   Ip4AutoConfigCallBack,\r
437                   IpSb,\r
438                   &IpSb->ReconfigEvent\r
439                   );\r
440 \r
441   if (EFI_ERROR (Status)) {\r
442     goto CLOSE_DONE_EVENT;\r
443   }\r
444 \r
445   //\r
446   // Open the EFI_IP4_CONFIG protocol then start auto configure\r
447   //\r
448   Status = gBS->OpenProtocol (\r
449                   IpSb->Controller,\r
450                   &gEfiIp4ConfigProtocolGuid,\r
451                   (VOID **) &Ip4Config,\r
452                   IpSb->Image,\r
453                   IpSb->Controller,\r
454                   EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE\r
455                   );\r
456 \r
457   if (EFI_ERROR (Status)) {\r
458     Status = EFI_UNSUPPORTED;\r
459     goto CLOSE_RECONFIG_EVENT;\r
460   }\r
461 \r
462   Status = Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);\r
463 \r
464   if (EFI_ERROR (Status)) {\r
465     gBS->CloseProtocol (\r
466            IpSb->Controller,\r
467            &gEfiIp4ConfigProtocolGuid,\r
468            IpSb->Image,\r
469            IpSb->Controller\r
470            );\r
471 \r
472     goto CLOSE_RECONFIG_EVENT;\r
473   }\r
474 \r
475   IpSb->Ip4Config = Ip4Config;\r
476   IpSb->State     = IP4_SERVICE_STARTED;\r
477   return Status;\r
478 \r
479 CLOSE_RECONFIG_EVENT:\r
480   gBS->CloseEvent (IpSb->ReconfigEvent);\r
481   IpSb->ReconfigEvent = NULL;\r
482 \r
483 CLOSE_DONE_EVENT:\r
484   gBS->CloseEvent (IpSb->DoneEvent);\r
485   IpSb->DoneEvent = NULL;\r
486 \r
487   return Status;\r
488 }\r
489 \r
490 \r
491 /**\r
492   Intiialize the IP4_PROTOCOL structure to the unconfigured states.\r
493 \r
494   @param  IpSb                   The IP4 service instance.\r
495   @param  IpInstance             The IP4 child instance.\r
496 \r
497   @return None\r
498 \r
499 **/\r
500 VOID\r
501 Ip4InitProtocol (\r
502   IN IP4_SERVICE            *IpSb,\r
503   IN IP4_PROTOCOL           *IpInstance\r
504   )\r
505 {\r
506   ASSERT ((IpSb != NULL) && (IpInstance != NULL));\r
507 \r
508   ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));\r
509 \r
510   IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;\r
511   CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));\r
512   IpInstance->State     = IP4_STATE_UNCONFIGED;\r
513   IpInstance->Service   = IpSb;\r
514 \r
515   InitializeListHead (&IpInstance->Link);\r
516   NetMapInit  (&IpInstance->RxTokens);\r
517   NetMapInit  (&IpInstance->TxTokens);\r
518   InitializeListHead (&IpInstance->Received);\r
519   InitializeListHead (&IpInstance->Delivered);\r
520   InitializeListHead (&IpInstance->AddrLink);\r
521 \r
522   EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);\r
523 }\r
524 \r
525 \r
526 /**\r
527   Configure the IP4 child. If the child is already configured,\r
528   change the configuration parameter. Otherwise configure it\r
529   for the first time. The caller should validate the configuration\r
530   before deliver them to it. It also don't do configure NULL.\r
531 \r
532   @param  IpInstance             The IP4 child to configure.\r
533   @param  Config                 The configure data.\r
534 \r
535   @retval EFI_SUCCESS            The IP4 child is successfully configured.\r
536   @retval EFI_DEVICE_ERROR       Failed to free the pending transive or to\r
537                                  configure  underlying MNP or other errors.\r
538   @retval EFI_NO_MAPPING         The IP4 child is configured to use default\r
539                                  address, but the default address hasn't been\r
540                                  configured. The IP4 child doesn't need to be\r
541                                  reconfigured when default address is configured.\r
542 \r
543 **/\r
544 EFI_STATUS\r
545 Ip4ConfigProtocol (\r
546   IN  IP4_PROTOCOL        *IpInstance,\r
547   IN  EFI_IP4_CONFIG_DATA *Config\r
548   )\r
549 {\r
550   IP4_SERVICE               *IpSb;\r
551   IP4_INTERFACE             *IpIf;\r
552   EFI_STATUS                Status;\r
553   IP4_ADDR                  Ip;\r
554   IP4_ADDR                  Netmask;\r
555 \r
556   IpSb = IpInstance->Service;\r
557 \r
558   //\r
559   // User is changing packet filters. It must be stopped\r
560   // before the station address can be changed.\r
561   //\r
562   if (IpInstance->State == IP4_STATE_CONFIGED) {\r
563     //\r
564     // Cancel all the pending transmit/receive from upper layer\r
565     //\r
566     Status = Ip4Cancel (IpInstance, NULL);\r
567 \r
568     if (EFI_ERROR (Status)) {\r
569       return EFI_DEVICE_ERROR;\r
570     }\r
571 \r
572     CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
573     return EFI_SUCCESS;\r
574   }\r
575 \r
576   //\r
577   // Configure a fresh IP4 protocol instance. Create a route table.\r
578   // Each IP child has its own route table, which may point to the\r
579   // default table if it is using default address.\r
580   //\r
581   Status                 = EFI_OUT_OF_RESOURCES;\r
582   IpInstance->RouteTable = Ip4CreateRouteTable ();\r
583 \r
584   if (IpInstance->RouteTable == NULL) {\r
585     return Status;\r
586   }\r
587 \r
588   //\r
589   // Set up the interface.\r
590   //\r
591   CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));\r
592   CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));\r
593 \r
594   Ip      = NTOHL (Ip);\r
595   Netmask = NTOHL (Netmask);\r
596 \r
597   if (!Config->UseDefaultAddress) {\r
598     //\r
599     // Find whether there is already an interface with the same\r
600     // station address. All the instances with the same station\r
601     // address shares one interface.\r
602     //\r
603     IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);\r
604 \r
605     if (IpIf != NULL) {\r
606       NET_GET_REF (IpIf);\r
607 \r
608     } else {\r
609       IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
610 \r
611       if (IpIf == NULL) {\r
612         goto ON_ERROR;\r
613       }\r
614 \r
615       Status = Ip4SetAddress (IpIf, Ip, Netmask);\r
616 \r
617       if (EFI_ERROR (Status)) {\r
618         Status = EFI_DEVICE_ERROR;\r
619         Ip4FreeInterface (IpIf, IpInstance);\r
620         goto ON_ERROR;\r
621       }\r
622 \r
623       InsertTailList (&IpSb->Interfaces, &IpIf->Link);\r
624     }\r
625 \r
626     //\r
627     // Add a route to this connected network in the route table\r
628     //\r
629     Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);\r
630 \r
631   } else {\r
632     //\r
633     // Use the default address. If the default configuration hasn't\r
634     // been started, start it.\r
635     //\r
636     if (IpSb->State == IP4_SERVICE_UNSTARTED) {\r
637       Status = Ip4StartAutoConfig (IpSb);\r
638 \r
639       if (EFI_ERROR (Status)) {\r
640         goto ON_ERROR;\r
641       }\r
642     }\r
643 \r
644     IpIf = IpSb->DefaultInterface;\r
645     NET_GET_REF (IpSb->DefaultInterface);\r
646 \r
647     //\r
648     // If default address is used, so is the default route table.\r
649     // Any route set by the instance has the precedence over the\r
650     // routes in the default route table. Link the default table\r
651     // after the instance's table. Routing will search the local\r
652     // table first.\r
653     //\r
654     NET_GET_REF (IpSb->DefaultRouteTable);\r
655     IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;\r
656   }\r
657 \r
658   IpInstance->Interface = IpIf;\r
659   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);\r
660 \r
661   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
662   IpInstance->State       = IP4_STATE_CONFIGED;\r
663 \r
664   //\r
665   // Although EFI_NO_MAPPING is an error code, the IP child has been\r
666   // successfully configured and doesn't need reconfiguration when\r
667   // default address is acquired.\r
668   //\r
669   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
670     return EFI_NO_MAPPING;\r
671   }\r
672 \r
673   return EFI_SUCCESS;\r
674 \r
675 ON_ERROR:\r
676   Ip4FreeRouteTable (IpInstance->RouteTable);\r
677   IpInstance->RouteTable = NULL;\r
678   return Status;\r
679 }\r
680 \r
681 \r
682 /**\r
683   Clean up the IP4 child, release all the resources used by it.\r
684 \r
685   @param  IpInstance             The IP4 child to clean up.\r
686 \r
687   @retval EFI_SUCCESS            The IP4 child is cleaned up\r
688   @retval EFI_DEVICE_ERROR       Some resources failed to be released\r
689 \r
690 **/\r
691 EFI_STATUS\r
692 Ip4CleanProtocol (\r
693   IN  IP4_PROTOCOL          *IpInstance\r
694   )\r
695 {\r
696   if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {\r
697     return EFI_DEVICE_ERROR;\r
698   }\r
699 \r
700   if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {\r
701     return EFI_DEVICE_ERROR;\r
702   }\r
703 \r
704   //\r
705   // Some packets haven't been recycled. It is because either the\r
706   // user forgets to recycle the packets, or because the callback\r
707   // hasn't been called. Just leave it alone.\r
708   //\r
709   if (!IsListEmpty (&IpInstance->Delivered)) {\r
710     ;\r
711   }\r
712 \r
713   if (IpInstance->Interface != NULL) {\r
714     RemoveEntryList (&IpInstance->AddrLink);\r
715     Ip4FreeInterface (IpInstance->Interface, IpInstance);\r
716     IpInstance->Interface = NULL;\r
717   }\r
718 \r
719   if (IpInstance->RouteTable != NULL) {\r
720     if (IpInstance->RouteTable->Next != NULL) {\r
721       Ip4FreeRouteTable (IpInstance->RouteTable->Next);\r
722     }\r
723 \r
724     Ip4FreeRouteTable (IpInstance->RouteTable);\r
725     IpInstance->RouteTable = NULL;\r
726   }\r
727 \r
728   if (IpInstance->EfiRouteTable != NULL) {\r
729     gBS->FreePool (IpInstance->EfiRouteTable);\r
730     IpInstance->EfiRouteTable = NULL;\r
731     IpInstance->EfiRouteCount = 0;\r
732   }\r
733 \r
734   if (IpInstance->Groups != NULL) {\r
735     gBS->FreePool (IpInstance->Groups);\r
736     IpInstance->Groups      = NULL;\r
737     IpInstance->GroupCount  = 0;\r
738   }\r
739 \r
740   NetMapClean (&IpInstance->TxTokens);\r
741 \r
742   NetMapClean (&IpInstance->RxTokens);\r
743 \r
744   return EFI_SUCCESS;\r
745 }\r
746 \r
747 \r
748 /**\r
749   Validate that Ip/Netmask pair is OK to be used as station\r
750   address. Only continuous netmasks are supported. and check\r
751   that StationAddress is a unicast address on the newtwork.\r
752 \r
753   @param  Ip                     The IP address to validate\r
754   @param  Netmask                The netmaks of the IP\r
755 \r
756   @retval TRUE                   The Ip/Netmask pair is valid\r
757   @retval FALSE                  The\r
758 \r
759 **/\r
760 BOOLEAN\r
761 Ip4StationAddressValid (\r
762   IN IP4_ADDR               Ip,\r
763   IN IP4_ADDR               Netmask\r
764   )\r
765 {\r
766   IP4_ADDR                  NetBrdcastMask;\r
767   INTN                      Len;\r
768   INTN                      Type;\r
769 \r
770   //\r
771   // Only support the station address with 0.0.0.0/0 to enable DHCP client.\r
772   //\r
773   if (Netmask == IP4_ALLZERO_ADDRESS) {\r
774     return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);\r
775   }\r
776 \r
777   //\r
778   // Only support the continuous net masks\r
779   //\r
780   if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {\r
781     return FALSE;\r
782   }\r
783 \r
784   //\r
785   // Station address can't be class D or class E address\r
786   //\r
787   if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {\r
788     return FALSE;\r
789   }\r
790 \r
791   //\r
792   // Station address can't be subnet broadcast/net broadcast address\r
793   //\r
794   if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {\r
795     return FALSE;\r
796   }\r
797 \r
798   NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];\r
799 \r
800   if (Ip == (Ip | ~NetBrdcastMask)) {\r
801     return FALSE;\r
802   }\r
803 \r
804   return TRUE;\r
805 }\r
806 \r
807 \r
808 /**\r
809   Configure the EFI_IP4_PROTOCOL instance. If IpConfigData is NULL,\r
810   the instance is cleaned up. If the instance hasn't been configure\r
811   before, it will be initialized. Otherwise, the filter setting of\r
812   the instance is updated.\r
813 \r
814   @param  This                   The IP4 child to configure\r
815   @param  IpConfigData           The configuration to apply. If NULL, clean it up.\r
816 \r
817   @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
818   @retval EFI_NO_MAPPING         The default address hasn't been configured and the\r
819                                  instance wants to use it.\r
820   @retval EFI_SUCCESS            The instance is configured.\r
821 \r
822 **/\r
823 EFI_STATUS\r
824 EFIAPI\r
825 EfiIp4Configure (\r
826   IN EFI_IP4_PROTOCOL       *This,\r
827   IN EFI_IP4_CONFIG_DATA    *IpConfigData       OPTIONAL\r
828   )\r
829 {\r
830   IP4_PROTOCOL              *IpInstance;\r
831   EFI_IP4_CONFIG_DATA       *Current;\r
832   EFI_TPL                   OldTpl;\r
833   EFI_STATUS                Status;\r
834   BOOLEAN                   AddrOk;\r
835   IP4_ADDR                  IpAddress;\r
836   IP4_ADDR                  SubnetMask;\r
837 \r
838   //\r
839   // First, validate the parameters\r
840   //\r
841   if (This == NULL) {\r
842     return EFI_INVALID_PARAMETER;\r
843   }\r
844 \r
845   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
846   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
847 \r
848   //\r
849   // Validate the configuration first.\r
850   //\r
851   if (IpConfigData != NULL) {\r
852     //\r
853     // This implementation doesn't support RawData\r
854     //\r
855     if (IpConfigData->RawData) {\r
856       Status = EFI_UNSUPPORTED;\r
857       goto ON_EXIT;\r
858     }\r
859 \r
860 \r
861     CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));\r
862     CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));\r
863 \r
864     IpAddress  = NTOHL (IpAddress);\r
865     SubnetMask = NTOHL (SubnetMask);\r
866 \r
867     //\r
868     // Check whether the station address is a valid unicast address\r
869     //\r
870     if (!IpConfigData->UseDefaultAddress) {\r
871       AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);\r
872 \r
873       if (!AddrOk) {\r
874         Status = EFI_INVALID_PARAMETER;\r
875         goto ON_EXIT;\r
876       }\r
877     }\r
878 \r
879     //\r
880     // User can only update packet filters when already configured.\r
881     // If it wants to change the station address, it must configure(NULL)\r
882     // the instance first.\r
883     //\r
884     if (IpInstance->State == IP4_STATE_CONFIGED) {\r
885       Current = &IpInstance->ConfigData;\r
886 \r
887       if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {\r
888         Status = EFI_ALREADY_STARTED;\r
889         goto ON_EXIT;\r
890       }\r
891 \r
892       if (!Current->UseDefaultAddress &&\r
893          (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||\r
894           !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {\r
895         Status = EFI_ALREADY_STARTED;\r
896         goto ON_EXIT;\r
897       }\r
898 \r
899       if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
900         return EFI_NO_MAPPING;\r
901       }\r
902     }\r
903   }\r
904 \r
905   //\r
906   // Configure the instance or clean it up.\r
907   //\r
908   if (IpConfigData != NULL) {\r
909     Status = Ip4ConfigProtocol (IpInstance, IpConfigData);\r
910   } else {\r
911     Status = Ip4CleanProtocol (IpInstance);\r
912 \r
913     //\r
914     // Don't change the state if it is DESTORY, consider the following\r
915     // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,\r
916     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,\r
917     // the unload fails miserably.\r
918     //\r
919     if (IpInstance->State == IP4_STATE_CONFIGED) {\r
920       IpInstance->State = IP4_STATE_UNCONFIGED;\r
921     }\r
922   }\r
923 \r
924   //\r
925   // Update the MNP's configure data. Ip4ServiceConfigMnp will check\r
926   // whether it is necessary to reconfigure the MNP.\r
927   //\r
928   Ip4ServiceConfigMnp (IpInstance->Service, FALSE);\r
929 \r
930   //\r
931   // Update the variable data.\r
932   //\r
933   Ip4SetVariableData (IpInstance->Service);\r
934 \r
935 ON_EXIT:\r
936   gBS->RestoreTPL (OldTpl);\r
937   return Status;\r
938 \r
939 }\r
940 \r
941 \r
942 /**\r
943   Change the IP4 child's multicast setting. The caller\r
944   should make sure that the parameters is valid.\r
945 \r
946   @param  IpInstance             The IP4 child to change the setting.\r
947   @param  JoinFlag               TRUE to join the group, otherwise leave it\r
948   @param  GroupAddress           The target group address\r
949 \r
950   @retval EFI_ALREADY_STARTED    Want to join the group, but already a member of it\r
951   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.\r
952   @retval EFI_DEVICE_ERROR       Failed to set the group configuraton\r
953   @retval EFI_SUCCESS            Successfully updated the group setting.\r
954   @retval EFI_NOT_FOUND          Try to leave the group which it isn't a member.\r
955 \r
956 **/\r
957 EFI_STATUS\r
958 Ip4Groups (\r
959   IN IP4_PROTOCOL           *IpInstance,\r
960   IN BOOLEAN                JoinFlag,\r
961   IN EFI_IPv4_ADDRESS       *GroupAddress       OPTIONAL\r
962   )\r
963 {\r
964   IP4_ADDR                  *Members;\r
965   IP4_ADDR                  Group;\r
966   UINT32                    Index;\r
967 \r
968   //\r
969   // Add it to the instance's Groups, and join the group by IGMP.\r
970   // IpInstance->Groups is in network byte order. IGMP operates in\r
971   // host byte order\r
972   //\r
973   if (JoinFlag) {\r
974     CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));\r
975 \r
976     for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
977       if (IpInstance->Groups[Index] == Group) {\r
978         return EFI_ALREADY_STARTED;\r
979       }\r
980     }\r
981 \r
982     Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);\r
983 \r
984     if (Members == NULL) {\r
985       return EFI_OUT_OF_RESOURCES;\r
986     }\r
987 \r
988     if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {\r
989       gBS->FreePool (Members);\r
990       return EFI_DEVICE_ERROR;\r
991     }\r
992 \r
993     if (IpInstance->Groups != NULL) {\r
994       gBS->FreePool (IpInstance->Groups);\r
995     }\r
996 \r
997     IpInstance->Groups = Members;\r
998     IpInstance->GroupCount++;\r
999 \r
1000     return EFI_SUCCESS;\r
1001   }\r
1002 \r
1003   //\r
1004   // Leave the group. Leave all the groups if GroupAddress is NULL.\r
1005   // Must iterate from the end to the beginning because the GroupCount\r
1006   // is decreamented each time an address is removed..\r
1007   //\r
1008   for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {\r
1009     Group = IpInstance->Groups[Index - 1];\r
1010 \r
1011     if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {\r
1012       if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {\r
1013         return EFI_DEVICE_ERROR;\r
1014       }\r
1015 \r
1016       Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);\r
1017       IpInstance->GroupCount--;\r
1018 \r
1019       if (IpInstance->GroupCount == 0) {\r
1020         ASSERT (Index == 1);\r
1021 \r
1022         gBS->FreePool (IpInstance->Groups);\r
1023         IpInstance->Groups = NULL;\r
1024       }\r
1025 \r
1026       if (GroupAddress != NULL) {\r
1027         return EFI_SUCCESS;\r
1028       }\r
1029     }\r
1030   }\r
1031 \r
1032   return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);\r
1033 }\r
1034 \r
1035 \r
1036 /**\r
1037   Change the IP4 child's multicast setting. If JoinFlag is true,\r
1038   the child wants to join the group. Otherwise it wants to leave\r
1039   the group. If JoinFlag is false, and GroupAddress is NULL,\r
1040   it will leave all the groups which is a member.\r
1041 \r
1042   @param  This                   The IP4 child to change the setting.\r
1043   @param  JoinFlag               TRUE to join the group, otherwise leave it.\r
1044   @param  GroupAddress           The target group address\r
1045 \r
1046   @retval EFI_INVALID_PARAMETER  The parameters are invalid\r
1047   @retval EFI_SUCCESS            The group setting has been changed.\r
1048   @retval Otherwise              It failed to change the setting.\r
1049 \r
1050 **/\r
1051 EFI_STATUS\r
1052 EFIAPI\r
1053 EfiIp4Groups (\r
1054   IN EFI_IP4_PROTOCOL       *This,\r
1055   IN BOOLEAN                JoinFlag,\r
1056   IN EFI_IPv4_ADDRESS       *GroupAddress     OPTIONAL\r
1057   )\r
1058 {\r
1059   IP4_PROTOCOL              *IpInstance;\r
1060   EFI_STATUS                Status;\r
1061   EFI_TPL                   OldTpl;\r
1062   IP4_ADDR                  McastIp;\r
1063 \r
1064   if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {\r
1065     return EFI_INVALID_PARAMETER;\r
1066   }\r
1067 \r
1068   if (GroupAddress != NULL) {\r
1069     CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));\r
1070 \r
1071     if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {\r
1072       return EFI_INVALID_PARAMETER;\r
1073     }\r
1074   }\r
1075 \r
1076   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1077   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
1078 \r
1079   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1080     Status = EFI_NOT_STARTED;\r
1081     goto ON_EXIT;\r
1082   }\r
1083 \r
1084   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
1085     Status = EFI_NO_MAPPING;\r
1086     goto ON_EXIT;\r
1087   }\r
1088 \r
1089   Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);\r
1090 \r
1091 ON_EXIT:\r
1092   gBS->RestoreTPL (OldTpl);\r
1093   return Status;\r
1094 }\r
1095 \r
1096 \r
1097 /**\r
1098   Modify the IP child's route table. Each instance has its own\r
1099   route table.\r
1100 \r
1101   @param  This                   The IP4 child to modify the route\r
1102   @param  DeleteRoute            TRUE to delete the route, otherwise add it\r
1103   @param  SubnetAddress          The destination network\r
1104   @param  SubnetMask             The destination network's mask\r
1105   @param  GatewayAddress         The next hop address.\r
1106 \r
1107   @retval EFI_INVALID_PARAMETER  The parameter is invalid.\r
1108   @retval EFI_SUCCESS            The route table is successfully modified.\r
1109   @retval Others                 Failed to modify the route table\r
1110 \r
1111 **/\r
1112 EFI_STATUS\r
1113 EFIAPI\r
1114 EfiIp4Routes (\r
1115   IN EFI_IP4_PROTOCOL       *This,\r
1116   IN BOOLEAN                DeleteRoute,\r
1117   IN EFI_IPv4_ADDRESS       *SubnetAddress,\r
1118   IN EFI_IPv4_ADDRESS       *SubnetMask,\r
1119   IN EFI_IPv4_ADDRESS       *GatewayAddress\r
1120   )\r
1121 {\r
1122   IP4_PROTOCOL              *IpInstance;\r
1123   IP4_INTERFACE             *IpIf;\r
1124   IP4_ADDR                  Dest;\r
1125   IP4_ADDR                  Netmask;\r
1126   IP4_ADDR                  Nexthop;\r
1127   EFI_STATUS                Status;\r
1128   EFI_TPL                   OldTpl;\r
1129 \r
1130   //\r
1131   // First, validate the parameters\r
1132   //\r
1133   if ((This == NULL) || (SubnetAddress == NULL) ||\r
1134       (SubnetMask == NULL) || (GatewayAddress == NULL)) {\r
1135     return EFI_INVALID_PARAMETER;\r
1136   }\r
1137 \r
1138   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1139   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);\r
1140 \r
1141   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1142     Status = EFI_NOT_STARTED;\r
1143     goto ON_EXIT;\r
1144   }\r
1145 \r
1146   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
1147     Status = EFI_NO_MAPPING;\r
1148     goto ON_EXIT;\r
1149   }\r
1150 \r
1151   CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));\r
1152   CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));\r
1153   CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));\r
1154 \r
1155   Dest    = NTOHL (Dest);\r
1156   Netmask = NTOHL (Netmask);\r
1157   Nexthop = NTOHL (Nexthop);\r
1158 \r
1159   IpIf    = IpInstance->Interface;\r
1160 \r
1161   if (!IP4_IS_VALID_NETMASK (Netmask)) {\r
1162     Status = EFI_INVALID_PARAMETER;\r
1163     goto ON_EXIT;\r
1164   }\r
1165 \r
1166   //\r
1167   // the gateway address must be a unicast on the connected network if not zero.\r
1168   //\r
1169   if ((Nexthop != IP4_ALLZERO_ADDRESS) &&\r
1170       (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||\r
1171         IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {\r
1172 \r
1173     Status = EFI_INVALID_PARAMETER;\r
1174     goto ON_EXIT;\r
1175   }\r
1176 \r
1177   if (DeleteRoute) {\r
1178     Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);\r
1179   } else {\r
1180     Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);\r
1181   }\r
1182 \r
1183 ON_EXIT:\r
1184   gBS->RestoreTPL (OldTpl);\r
1185   return Status;\r
1186 }\r
1187 \r
1188 \r
1189 /**\r
1190   Check whether the user's token or event has already\r
1191   been enqueue on IP4's list.\r
1192 \r
1193   @param  Map                    The container of either user's transmit or receive\r
1194                                  token.\r
1195   @param  Item                   Current item to check against\r
1196   @param  Context                The Token to check againist.\r
1197 \r
1198   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP\r
1199   @retval EFI_SUCCESS            The current item isn't the same token/event as the\r
1200                                  context.\r
1201 \r
1202 **/\r
1203 EFI_STATUS\r
1204 Ip4TokenExist (\r
1205   IN NET_MAP                *Map,\r
1206   IN NET_MAP_ITEM           *Item,\r
1207   IN VOID                   *Context\r
1208   )\r
1209 {\r
1210   EFI_IP4_COMPLETION_TOKEN  *Token;\r
1211   EFI_IP4_COMPLETION_TOKEN  *TokenInItem;\r
1212 \r
1213   Token       = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
1214   TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;\r
1215 \r
1216   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
1217     return EFI_ACCESS_DENIED;\r
1218   }\r
1219 \r
1220   return EFI_SUCCESS;\r
1221 }\r
1222 \r
1223 \r
1224 /**\r
1225   Validate the user's token against current station address.\r
1226 \r
1227   @param  Token                  User's token to validate\r
1228   @param  IpIf                   The IP4 child's interface.\r
1229 \r
1230   @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
1231   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.\r
1232   @retval EFI_SUCCESS            The token is OK\r
1233 \r
1234 **/\r
1235 EFI_STATUS\r
1236 Ip4TxTokenValid (\r
1237   IN EFI_IP4_COMPLETION_TOKEN   *Token,\r
1238   IN IP4_INTERFACE              *IpIf\r
1239   )\r
1240 {\r
1241   EFI_IP4_TRANSMIT_DATA     *TxData;\r
1242   EFI_IP4_OVERRIDE_DATA     *Override;\r
1243   IP4_ADDR                  Src;\r
1244   IP4_ADDR                  Gateway;\r
1245   UINT32                    Offset;\r
1246   UINT32                    Index;\r
1247   UINT32                    HeadLen;\r
1248 \r
1249   if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {\r
1250     return EFI_INVALID_PARAMETER;\r
1251   }\r
1252 \r
1253   TxData = Token->Packet.TxData;\r
1254 \r
1255   //\r
1256   // Check the IP options: no more than 40 bytes and format is OK\r
1257   //\r
1258   if (TxData->OptionsLength != 0) {\r
1259     if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {\r
1260       return EFI_INVALID_PARAMETER;\r
1261     }\r
1262 \r
1263     if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {\r
1264       return EFI_INVALID_PARAMETER;\r
1265     }\r
1266   }\r
1267 \r
1268   //\r
1269   // Check the fragment table: no empty fragment, and length isn't bogus\r
1270   //\r
1271   if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {\r
1272     return EFI_INVALID_PARAMETER;\r
1273   }\r
1274 \r
1275   Offset = TxData->TotalDataLength;\r
1276 \r
1277   for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
1278     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||\r
1279         (TxData->FragmentTable[Index].FragmentLength == 0)) {\r
1280 \r
1281       return EFI_INVALID_PARAMETER;\r
1282     }\r
1283 \r
1284     Offset -= TxData->FragmentTable[Index].FragmentLength;\r
1285   }\r
1286 \r
1287   if (Offset != 0) {\r
1288     return EFI_INVALID_PARAMETER;\r
1289   }\r
1290 \r
1291   //\r
1292   // Check the source and gateway: they must be a valid unicast.\r
1293   // Gateway must also be on the connected network.\r
1294   //\r
1295   if (TxData->OverrideData) {\r
1296     Override = TxData->OverrideData;\r
1297 \r
1298     CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
1299     CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
1300 \r
1301     Src     = NTOHL (Src);\r
1302     Gateway = NTOHL (Gateway);\r
1303 \r
1304     if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||\r
1305         (Src == IP4_ALLONE_ADDRESS) ||\r
1306         IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
1307 \r
1308       return EFI_INVALID_PARAMETER;\r
1309     }\r
1310 \r
1311     //\r
1312     // If gateway isn't zero, it must be a unicast address, and\r
1313     // on the connected network.\r
1314     //\r
1315     if ((Gateway != IP4_ALLZERO_ADDRESS) &&\r
1316         ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||\r
1317          !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||\r
1318          IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {\r
1319 \r
1320       return EFI_INVALID_PARAMETER;\r
1321     }\r
1322   }\r
1323 \r
1324   //\r
1325   // Check the packet length: Head length and packet length all has a limit\r
1326   //\r
1327   HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);\r
1328 \r
1329   if ((HeadLen > IP4_MAX_HEADLEN) ||\r
1330       (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {\r
1331 \r
1332     return EFI_BAD_BUFFER_SIZE;\r
1333   }\r
1334 \r
1335   return EFI_SUCCESS;\r
1336 }\r
1337 \r
1338 \r
1339 /**\r
1340   The callback function for the net buffer which wraps the user's\r
1341   transmit token. Although it seems this function is pretty simple,\r
1342   there are some subtle things.\r
1343   When user requests the IP to transmit a packet by passing it a\r
1344   token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data\r
1345   is wrapped in an net buffer. the net buffer's Free function is\r
1346   set to Ip4FreeTxToken. The Token and token wrap are added to the\r
1347   IP child's TxToken map. Then the buffer is passed to Ip4Output for\r
1348   transmission. If something error happened before that, the buffer\r
1349   is freed, which in turn will free the token wrap. The wrap may\r
1350   have been added to the TxToken map or not, and the user's event\r
1351   shouldn't be fired because we are still in the EfiIp4Transmit. If\r
1352   the buffer has been sent by Ip4Output, it should be removed from\r
1353   the TxToken map and user's event signaled. The token wrap and buffer\r
1354   are bound together. Check the comments in Ip4Output for information\r
1355   about IP fragmentation.\r
1356 \r
1357   @param  Context                The token's wrap\r
1358 \r
1359   @return None\r
1360 \r
1361 **/\r
1362 VOID\r
1363 Ip4FreeTxToken (\r
1364   IN VOID                   *Context\r
1365   )\r
1366 {\r
1367   IP4_TXTOKEN_WRAP          *Wrap;\r
1368   NET_MAP_ITEM              *Item;\r
1369 \r
1370   Wrap = (IP4_TXTOKEN_WRAP *) Context;\r
1371 \r
1372   //\r
1373   // Find the token in the instance's map. EfiIp4Transmit put the\r
1374   // token to the map. If that failed, NetMapFindKey will return NULL.\r
1375   //\r
1376   Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);\r
1377 \r
1378   if (Item != NULL) {\r
1379     NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);\r
1380   }\r
1381 \r
1382   if (Wrap->Sent) {\r
1383     gBS->SignalEvent (Wrap->Token->Event);\r
1384 \r
1385     //\r
1386     // Dispatch the DPC queued by the NotifyFunction of Token->Event.\r
1387     //\r
1388     NetLibDispatchDpc ();\r
1389   }\r
1390 \r
1391   gBS->FreePool (Wrap);\r
1392 }\r
1393 \r
1394 \r
1395 /**\r
1396   The callback function to Ip4Output to update the transmit status.\r
1397 \r
1398   @param  Ip4Instance            The Ip4Instance that request the transmit.\r
1399   @param  Packet                 The user's transmit request\r
1400   @param  IoStatus               The result of the transmission\r
1401   @param  Flag                   Not used during transmission\r
1402   @param  Context                The token's wrap.\r
1403 \r
1404   @return None\r
1405 \r
1406 **/\r
1407 VOID\r
1408 Ip4OnPacketSent (\r
1409   IP4_PROTOCOL              *Ip4Instance,\r
1410   NET_BUF                   *Packet,\r
1411   EFI_STATUS                IoStatus,\r
1412   UINT32                    Flag,\r
1413   VOID                      *Context\r
1414   )\r
1415 {\r
1416   IP4_TXTOKEN_WRAP          *Wrap;\r
1417 \r
1418   //\r
1419   // This is the transmission request from upper layer,\r
1420   // not the IP4 driver itself.\r
1421   //\r
1422   ASSERT (Ip4Instance != NULL);\r
1423 \r
1424   //\r
1425   // The first fragment of the packet has been sent. Update\r
1426   // the token's status. That is, if fragmented, the transmit's\r
1427   // status is the first fragment's status. The Wrap will be\r
1428   // release when all the fragments are release. Check the comments\r
1429   // in Ip4FreeTxToken and Ip4Output for information.\r
1430   //\r
1431   Wrap                = (IP4_TXTOKEN_WRAP *) Context;\r
1432   Wrap->Token->Status = IoStatus;\r
1433 \r
1434   NetbufFree (Wrap->Packet);\r
1435 }\r
1436 \r
1437 \r
1438 /**\r
1439   Transmit the user's data asynchronously. When transmission\r
1440   completed,the Token's status is updated and its event signalled.\r
1441 \r
1442   @param  This                   The IP4 child instance\r
1443   @param  Token                  The user's transmit token, which contains user's\r
1444                                  data, the result and an event to signal when\r
1445                                  completed.\r
1446 \r
1447   @retval EFI_INVALID_PARAMETER  The parameter is invalid.\r
1448   @retval EFI_NOT_STARTED        The IP4 child hasn't been started.\r
1449   @retval EFI_SUCCESS            The user's data has been successfully enqueued\r
1450                                  for transmission.\r
1451 \r
1452 **/\r
1453 EFI_STATUS\r
1454 EFIAPI\r
1455 EfiIp4Transmit (\r
1456   IN EFI_IP4_PROTOCOL         *This,\r
1457   IN EFI_IP4_COMPLETION_TOKEN *Token\r
1458   )\r
1459 {\r
1460   IP4_SERVICE               *IpSb;\r
1461   IP4_PROTOCOL              *IpInstance;\r
1462   IP4_INTERFACE             *IpIf;\r
1463   IP4_TXTOKEN_WRAP          *Wrap;\r
1464   EFI_IP4_TRANSMIT_DATA     *TxData;\r
1465   EFI_IP4_CONFIG_DATA       *Config;\r
1466   EFI_IP4_OVERRIDE_DATA     *Override;\r
1467   IP4_HEAD                  Head;\r
1468   IP4_ADDR                  GateWay;\r
1469   EFI_STATUS                Status;\r
1470   EFI_TPL                   OldTpl;\r
1471   BOOLEAN                   DontFragment;\r
1472   UINT32                    HeadLen;\r
1473 \r
1474   if (This == NULL) {\r
1475     return EFI_INVALID_PARAMETER;\r
1476   }\r
1477 \r
1478   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1479 \r
1480   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1481     return EFI_NOT_STARTED;\r
1482   }\r
1483 \r
1484   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
1485 \r
1486   IpSb    = IpInstance->Service;\r
1487   IpIf    = IpInstance->Interface;\r
1488   Config  = &IpInstance->ConfigData;\r
1489 \r
1490   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
1491     Status = EFI_NO_MAPPING;\r
1492     goto ON_EXIT;\r
1493   }\r
1494 \r
1495   //\r
1496   // make sure that token is properly formated\r
1497   //\r
1498   Status = Ip4TxTokenValid (Token, IpIf);\r
1499 \r
1500   if (EFI_ERROR (Status)) {\r
1501     goto ON_EXIT;\r
1502   }\r
1503 \r
1504   //\r
1505   // Check whether the token or signal already existed.\r
1506   //\r
1507   if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {\r
1508     Status = EFI_ACCESS_DENIED;\r
1509     goto ON_EXIT;\r
1510   }\r
1511 \r
1512   //\r
1513   // Build the IP header, need to fill in the Tos, TotalLen, Id,\r
1514   // fragment, Ttl, protocol, Src, and Dst.\r
1515   //\r
1516   TxData = Token->Packet.TxData;\r
1517 \r
1518   CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));\r
1519   Head.Dst = NTOHL (Head.Dst);\r
1520 \r
1521   if (TxData->OverrideData) {\r
1522     Override      = TxData->OverrideData;\r
1523     Head.Protocol = Override->Protocol;\r
1524     Head.Tos      = Override->TypeOfService;\r
1525     Head.Ttl      = Override->TimeToLive;\r
1526     DontFragment  = Override->DoNotFragment;\r
1527 \r
1528     CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
1529     CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
1530 \r
1531     Head.Src = NTOHL (Head.Src);\r
1532     GateWay  = NTOHL (GateWay);\r
1533   } else {\r
1534     Head.Src      = IpIf->Ip;\r
1535     GateWay       = IP4_ALLZERO_ADDRESS;\r
1536     Head.Protocol = Config->DefaultProtocol;\r
1537     Head.Tos      = Config->TypeOfService;\r
1538     Head.Ttl      = Config->TimeToLive;\r
1539     DontFragment  = Config->DoNotFragment;\r
1540   }\r
1541 \r
1542   Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);\r
1543   HeadLen       = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);\r
1544 \r
1545   //\r
1546   // If don't fragment and fragment needed, return error\r
1547   //\r
1548   if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->SnpMode.MaxPacketSize)) {\r
1549     Status = EFI_BAD_BUFFER_SIZE;\r
1550     goto ON_EXIT;\r
1551   }\r
1552 \r
1553   //\r
1554   // OK, it survives all the validation check. Wrap the token in\r
1555   // a IP4_TXTOKEN_WRAP and the data in a netbuf\r
1556   //\r
1557   Status = EFI_OUT_OF_RESOURCES;\r
1558   Wrap   = AllocatePool (sizeof (IP4_TXTOKEN_WRAP));\r
1559   if (Wrap == NULL) {\r
1560     goto ON_EXIT;\r
1561   }\r
1562 \r
1563   Wrap->IpInstance  = IpInstance;\r
1564   Wrap->Token       = Token;\r
1565   Wrap->Sent        = FALSE;\r
1566   Wrap->Life        = IP4_US_TO_SEC (Config->TransmitTimeout);\r
1567   Wrap->Packet      = NetbufFromExt (\r
1568                         (NET_FRAGMENT *) TxData->FragmentTable,\r
1569                         TxData->FragmentCount,\r
1570                         IP4_MAX_HEADLEN,\r
1571                         0,\r
1572                         Ip4FreeTxToken,\r
1573                         Wrap\r
1574                         );\r
1575 \r
1576   if (Wrap->Packet == NULL) {\r
1577     gBS->FreePool (Wrap);\r
1578     goto ON_EXIT;\r
1579   }\r
1580 \r
1581   Token->Status = EFI_NOT_READY;\r
1582 \r
1583   if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {\r
1584     //\r
1585     // NetbufFree will call Ip4FreeTxToken, which in turn will\r
1586     // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been\r
1587     // enqueued.\r
1588     //\r
1589     NetbufFree (Wrap->Packet);\r
1590     goto ON_EXIT;\r
1591   }\r
1592 \r
1593   //\r
1594   // Mark the packet sent before output it. Mark it not sent again if the\r
1595   // returned status is not EFI_SUCCESS;\r
1596   //\r
1597   Wrap->Sent = TRUE;\r
1598 \r
1599   Status = Ip4Output (\r
1600              IpSb,\r
1601              IpInstance,\r
1602              Wrap->Packet,\r
1603              &Head,\r
1604              TxData->OptionsBuffer,\r
1605              TxData->OptionsLength,\r
1606              GateWay,\r
1607              Ip4OnPacketSent,\r
1608              Wrap\r
1609              );\r
1610 \r
1611   if (EFI_ERROR (Status)) {\r
1612     Wrap->Sent = FALSE;\r
1613     NetbufFree (Wrap->Packet);\r
1614   }\r
1615 \r
1616 ON_EXIT:\r
1617   gBS->RestoreTPL (OldTpl);\r
1618   return Status;\r
1619 }\r
1620 \r
1621 \r
1622 /**\r
1623   Receive a packet for the upper layer. If there are packets\r
1624   pending on the child's receive queue, the receive request\r
1625   will be fulfilled immediately. Otherwise, the request is\r
1626   enqueued. When receive request is completed, the status in\r
1627   the Token is updated and its event is signalled.\r
1628 \r
1629   @param  This                   The IP4 child to receive packet.\r
1630   @param  Token                  The user's receive token\r
1631 \r
1632   @retval EFI_INVALID_PARAMETER  The token is invalid.\r
1633   @retval EFI_NOT_STARTED        The IP4 child hasn't been started\r
1634   @retval EFI_ACCESS_DENIED      The token or event is already queued.\r
1635   @retval EFI_SUCCESS            The receive request has been issued.\r
1636 \r
1637 **/\r
1638 EFI_STATUS\r
1639 EFIAPI\r
1640 EfiIp4Receive (\r
1641   IN EFI_IP4_PROTOCOL         *This,\r
1642   IN EFI_IP4_COMPLETION_TOKEN *Token\r
1643   )\r
1644 {\r
1645   IP4_PROTOCOL              *IpInstance;\r
1646   EFI_STATUS                Status;\r
1647   EFI_TPL                   OldTpl;\r
1648 \r
1649   //\r
1650   // First validate the parameters\r
1651   //\r
1652   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {\r
1653     return EFI_INVALID_PARAMETER;\r
1654   }\r
1655 \r
1656   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1657 \r
1658   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1659 \r
1660   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1661     Status = EFI_NOT_STARTED;\r
1662     goto ON_EXIT;\r
1663   }\r
1664 \r
1665   //\r
1666   // Check whether the toke is already on the receive queue.\r
1667   //\r
1668   Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);\r
1669 \r
1670   if (EFI_ERROR (Status)) {\r
1671     Status = EFI_ACCESS_DENIED;\r
1672     goto ON_EXIT;\r
1673   }\r
1674 \r
1675   //\r
1676   // Queue the token then check whether there is pending received packet.\r
1677   //\r
1678   Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);\r
1679 \r
1680   if (EFI_ERROR (Status)) {\r
1681     goto ON_EXIT;\r
1682   }\r
1683 \r
1684   Status = Ip4InstanceDeliverPacket (IpInstance);\r
1685 \r
1686   //\r
1687   // Dispatch the DPC queued by the NotifyFunction of this instane's receive\r
1688   // event.\r
1689   //\r
1690   NetLibDispatchDpc ();\r
1691 \r
1692 ON_EXIT:\r
1693   gBS->RestoreTPL (OldTpl);\r
1694   return Status;\r
1695 }\r
1696 \r
1697 \r
1698 /**\r
1699   Cancel the transmitted but not recycled packet. If a matching\r
1700   token is found, it will call Ip4CancelPacket to cancel the\r
1701   packet. Ip4CancelPacket will cancel all the fragments of the\r
1702   packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP\r
1703   will be deleted from the Map, and user's event signalled.\r
1704   Because Ip4CancelPacket and other functions are all called in\r
1705   line, so, after Ip4CancelPacket returns, the Item has been freed.\r
1706 \r
1707   @param  Map                    The IP4 child's transmit queue\r
1708   @param  Item                   The current transmitted packet to test.\r
1709   @param  Context                The user's token to cancel.\r
1710 \r
1711   @retval EFI_SUCCESS            Continue to check the next Item.\r
1712   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.\r
1713 \r
1714 **/\r
1715 EFI_STATUS\r
1716 Ip4CancelTxTokens (\r
1717   IN NET_MAP                *Map,\r
1718   IN NET_MAP_ITEM           *Item,\r
1719   IN VOID                   *Context\r
1720   )\r
1721 {\r
1722   EFI_IP4_COMPLETION_TOKEN  *Token;\r
1723   IP4_TXTOKEN_WRAP          *Wrap;\r
1724 \r
1725   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
1726 \r
1727   //\r
1728   // Return EFI_SUCCESS to check the next item in the map if\r
1729   // this one doesn't match.\r
1730   //\r
1731   if ((Token != NULL) && (Token != Item->Key)) {\r
1732     return EFI_SUCCESS;\r
1733   }\r
1734 \r
1735   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;\r
1736   ASSERT (Wrap != NULL);\r
1737 \r
1738   //\r
1739   // Don't access the Item, Wrap and Token's members after this point.\r
1740   // Item and wrap has been freed. And we no longer own the Token.\r
1741   //\r
1742   Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
1743 \r
1744   //\r
1745   // If only one item is to be cancel, return EFI_ABORTED to stop\r
1746   // iterating the map any more.\r
1747   //\r
1748   if (Token != NULL) {\r
1749     return EFI_ABORTED;\r
1750   }\r
1751 \r
1752   return EFI_SUCCESS;\r
1753 }\r
1754 \r
1755 \r
1756 /**\r
1757   Cancel the receive request. This is quiet simple, because\r
1758   it is only enqueued in our local receive map.\r
1759 \r
1760   @param  Map                    The IP4 child's receive queue\r
1761   @param  Item                   Current receive request to cancel.\r
1762   @param  Context                The user's token to cancel\r
1763 \r
1764   @retval EFI_SUCCESS            Continue to check the next receive request on the\r
1765                                  queue.\r
1766   @retval EFI_ABORTED            The user's token (token != NULL) has been\r
1767                                  cancelled.\r
1768 \r
1769 **/\r
1770 EFI_STATUS\r
1771 Ip4CancelRxTokens (\r
1772   IN NET_MAP                *Map,\r
1773   IN NET_MAP_ITEM           *Item,\r
1774   IN VOID                   *Context\r
1775   )\r
1776 {\r
1777   EFI_IP4_COMPLETION_TOKEN  *Token;\r
1778   EFI_IP4_COMPLETION_TOKEN  *This;\r
1779 \r
1780   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
1781   This  = Item->Key;\r
1782 \r
1783   if ((Token != NULL) && (Token != This)) {\r
1784     return EFI_SUCCESS;\r
1785   }\r
1786 \r
1787   NetMapRemoveItem (Map, Item, NULL);\r
1788 \r
1789   This->Status        = EFI_ABORTED;\r
1790   This->Packet.RxData = NULL;\r
1791   gBS->SignalEvent (This->Event);\r
1792 \r
1793   if (Token != NULL) {\r
1794     return EFI_ABORTED;\r
1795   }\r
1796 \r
1797   return EFI_SUCCESS;\r
1798 }\r
1799 \r
1800 \r
1801 /**\r
1802   Cancel the user's receive/transmit request.\r
1803 \r
1804   @param  IpInstance             The IP4 child\r
1805   @param  Token                  The token to cancel. If NULL, all token will be\r
1806                                  cancelled.\r
1807 \r
1808   @retval EFI_SUCCESS            The token is cancelled\r
1809   @retval EFI_NOT_FOUND          The token isn't found on either the\r
1810                                  transmit/receive queue\r
1811   @retval EFI_DEVICE_ERROR       Not all token is cancelled when Token is NULL.\r
1812 \r
1813 **/\r
1814 EFI_STATUS\r
1815 Ip4Cancel (\r
1816   IN IP4_PROTOCOL             *IpInstance,\r
1817   IN EFI_IP4_COMPLETION_TOKEN *Token          OPTIONAL\r
1818   )\r
1819 {\r
1820   EFI_STATUS                Status;\r
1821 \r
1822   //\r
1823   // First check the transmitted packet. Ip4CancelTxTokens returns\r
1824   // EFI_ABORTED to mean that the token has been cancelled when\r
1825   // token != NULL. So, return EFI_SUCCESS for this condition.\r
1826   //\r
1827   Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);\r
1828 \r
1829   if (EFI_ERROR (Status)) {\r
1830     if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
1831       return EFI_SUCCESS;\r
1832     }\r
1833 \r
1834     return Status;\r
1835   }\r
1836 \r
1837   //\r
1838   // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT\r
1839   // for Token!=NULL and it is cancelled.\r
1840   //\r
1841   Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);\r
1842   //\r
1843   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's\r
1844   // events.\r
1845   //\r
1846   NetLibDispatchDpc ();\r
1847   if (EFI_ERROR (Status)) {\r
1848     if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
1849       return EFI_SUCCESS;\r
1850     }\r
1851 \r
1852     return Status;\r
1853   }\r
1854 \r
1855   //\r
1856   // OK, if the Token is found when Token != NULL, the NetMapIterate\r
1857   // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.\r
1858   //\r
1859   if (Token != NULL) {\r
1860     return EFI_NOT_FOUND;\r
1861   }\r
1862 \r
1863   //\r
1864   // If Token == NULL, cancel all the tokens. return error if no\r
1865   // all of them are cancelled.\r
1866   //\r
1867   if (!NetMapIsEmpty (&IpInstance->TxTokens) ||\r
1868       !NetMapIsEmpty (&IpInstance->RxTokens)) {\r
1869 \r
1870     return EFI_DEVICE_ERROR;\r
1871   }\r
1872 \r
1873   return EFI_SUCCESS;\r
1874 }\r
1875 \r
1876 \r
1877 /**\r
1878   Cancel the queued receive/transmit requests. If Token is NULL,\r
1879   all the queued requests will be cancelled. It just validate\r
1880   the parameter then pass them to Ip4Cancel.\r
1881 \r
1882   @param  This                   The IP4 child to cancel the request\r
1883   @param  Token                  The token to cancel, if NULL, cancel all.\r
1884 \r
1885   @retval EFI_INVALID_PARAMETER  This is NULL\r
1886   @retval EFI_NOT_STARTED        The IP4 child hasn't been configured.\r
1887   @retval EFI_NO_MAPPING         The IP4 child is configured to use the default,\r
1888                                  but the default address hasn't been acquired.\r
1889   @retval EFI_SUCCESS            The Token is cancelled.\r
1890 \r
1891 **/\r
1892 EFI_STATUS\r
1893 EFIAPI\r
1894 EfiIp4Cancel (\r
1895   IN EFI_IP4_PROTOCOL         *This,\r
1896   IN EFI_IP4_COMPLETION_TOKEN *Token    OPTIONAL\r
1897   )\r
1898 {\r
1899   IP4_PROTOCOL              *IpInstance;\r
1900   EFI_STATUS                Status;\r
1901   EFI_TPL                   OldTpl;\r
1902 \r
1903   if (This == NULL) {\r
1904     return EFI_INVALID_PARAMETER;\r
1905   }\r
1906 \r
1907   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1908 \r
1909   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1910 \r
1911   if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1912     Status = EFI_NOT_STARTED;\r
1913     goto ON_EXIT;\r
1914   }\r
1915 \r
1916   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
1917     Status = EFI_NO_MAPPING;\r
1918     goto ON_EXIT;\r
1919   }\r
1920 \r
1921   Status = Ip4Cancel (IpInstance, Token);\r
1922 \r
1923 ON_EXIT:\r
1924   gBS->RestoreTPL (OldTpl);\r
1925   return Status;\r
1926 }\r
1927 \r
1928 \r
1929 /**\r
1930   Poll the network stack. The EFI network stack is poll based. There\r
1931   is no interrupt support for the network interface card.\r
1932 \r
1933   @param  This                   The IP4 child to poll through\r
1934 \r
1935   @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
1936   @retval EFI_NOT_STARTED        The IP4 child hasn't been configured.\r
1937 \r
1938 **/\r
1939 EFI_STATUS\r
1940 EFIAPI\r
1941 EfiIp4Poll (\r
1942   IN EFI_IP4_PROTOCOL       *This\r
1943   )\r
1944 {\r
1945   IP4_PROTOCOL                  *IpInstance;\r
1946   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;\r
1947 \r
1948   if (This == NULL) {\r
1949     return EFI_INVALID_PARAMETER;\r
1950   }\r
1951 \r
1952   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
1953 \r
1954   if (IpInstance->State == IP4_STATE_UNCONFIGED) {\r
1955     return EFI_NOT_STARTED;\r
1956   }\r
1957 \r
1958   Mnp = IpInstance->Service->Mnp;\r
1959 \r
1960   //\r
1961   // Don't lock the Poll function to enable the deliver of\r
1962   // the packet polled up.\r
1963   //\r
1964   return Mnp->Poll (Mnp);\r
1965 }\r
1966 \r
1967 EFI_IP4_PROTOCOL\r
1968 mEfiIp4ProtocolTemplete = {\r
1969   EfiIp4GetModeData,\r
1970   EfiIp4Configure,\r
1971   EfiIp4Groups,\r
1972   EfiIp4Routes,\r
1973   EfiIp4Transmit,\r
1974   EfiIp4Receive,\r
1975   EfiIp4Cancel,\r
1976   EfiIp4Poll\r
1977 };\r
1978 \r
1979 \r
1980 /**\r
1981   Decrease the life of the transmitted packets. If it is\r
1982   decreased to zero, cancel the packet. This function is\r
1983   called by Ip4packetTimerTicking which time out both the\r
1984   received-but-not-delivered and transmitted-but-not-recycle\r
1985   packets.\r
1986 \r
1987   @param  Map                    The IP4 child's transmit map.\r
1988   @param  Item                   Current transmitted packet\r
1989   @param  Context                Not used.\r
1990 \r
1991   @retval EFI_SUCCESS            Always returns EFI_SUCCESS\r
1992 \r
1993 **/\r
1994 EFI_STATUS\r
1995 Ip4SentPacketTicking (\r
1996   IN NET_MAP                *Map,\r
1997   IN NET_MAP_ITEM           *Item,\r
1998   IN VOID                   *Context\r
1999   )\r
2000 {\r
2001   IP4_TXTOKEN_WRAP          *Wrap;\r
2002 \r
2003   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;\r
2004   ASSERT (Wrap != NULL);\r
2005 \r
2006   if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {\r
2007     Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
2008   }\r
2009 \r
2010   return EFI_SUCCESS;\r
2011 }\r
2012 \r
2013 \r
2014 /**\r
2015   The heart beat timer of IP4 service instance. It times out\r
2016   all of its IP4 children's received-but-not-delivered and\r
2017   transmitted-but-not-recycle packets, and provides time input\r
2018   for its IGMP protocol.\r
2019 \r
2020   @param  Event                  The IP4 service instance's heart beat timer.\r
2021   @param  Context                The IP4 service instance.\r
2022 \r
2023   @return None\r
2024 \r
2025 **/\r
2026 VOID\r
2027 EFIAPI\r
2028 Ip4TimerTicking (\r
2029   IN EFI_EVENT              Event,\r
2030   IN VOID                   *Context\r
2031   )\r
2032 {\r
2033   IP4_SERVICE               *IpSb;\r
2034 \r
2035   IpSb = (IP4_SERVICE *) Context;\r
2036   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
2037 \r
2038   Ip4PacketTimerTicking (IpSb);\r
2039   Ip4IgmpTicking (IpSb);\r
2040 }\r