]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Impl.c
CommitLineData
772db4bb 1/** @file\r
2\r
3Copyright (c) 2005 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12\r
13Module Name:\r
14\r
15 Ip4Impl.c\r
16\r
17Abstract:\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
772db4bb 39EFI_STATUS\r
40EFIAPI\r
41EfiIp4GetModeData (\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
e48e37fc 59 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
687a2e5f 69 CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));\r
772db4bb 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
e48e37fc 91 CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 92\r
93 Ip = HTONL (IpInstance->Interface->SubnetMask);\r
e48e37fc 94 CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 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
e48e37fc 104 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
687a2e5f 114 CopyMem (MnpConfigData, &IpSb->MnpConfigData, sizeof (*MnpConfigData));\r
772db4bb 115 }\r
116\r
117 if (SnpModeData != NULL) {\r
687a2e5f 118 CopyMem (SnpModeData, &IpSb->SnpMode, sizeof (*SnpModeData));\r
772db4bb 119 }\r
120\r
e48e37fc 121 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
144EFI_STATUS\r
145Ip4ServiceConfigMnp (\r
146 IN IP4_SERVICE *IpSb,\r
147 IN BOOLEAN Force\r
148 )\r
149{\r
e48e37fc 150 LIST_ENTRY *Entry;\r
151 LIST_ENTRY *ProtoEntry;\r
772db4bb 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
687a2e5f 199 IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;\r
772db4bb 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
772db4bb 216 @param Context The IP4 service binding instance.\r
217\r
218 @return None\r
219\r
220**/\r
221VOID\r
222EFIAPI\r
36ee91ca 223Ip4AutoConfigCallBackDpc (\r
772db4bb 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
36ee91ca 252 if (IpSb->ActiveEvent == IpSb->ReconfigEvent) {\r
772db4bb 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
e48e37fc 273 InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
772db4bb 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
e48e37fc 293 Data = AllocatePool (Len);\r
772db4bb 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
356ON_EXIT:\r
e48e37fc 357 gBS->FreePool (Data);\r
772db4bb 358}\r
359\r
36ee91ca 360VOID\r
361EFIAPI\r
362Ip4AutoConfigCallBack (\r
363 IN EFI_EVENT Event,\r
364 IN VOID *Context\r
365 )\r
366/*++\r
367\r
368Routine Description:\r
369\r
370 Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK\r
371\r
372Arguments:\r
373\r
374 Event - The event that is signalled.\r
375 Context - The IP4 service binding instance.\r
376\r
377Returns:\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
772db4bb 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
406EFI_STATUS\r
407Ip4StartAutoConfig (\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
e48e37fc 423 TPL_CALLBACK,\r
772db4bb 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
e48e37fc 435 TPL_NOTIFY,\r
772db4bb 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
479CLOSE_RECONFIG_EVENT:\r
480 gBS->CloseEvent (IpSb->ReconfigEvent);\r
481 IpSb->ReconfigEvent = NULL;\r
482\r
483CLOSE_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
500VOID\r
501Ip4InitProtocol (\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
e48e37fc 508 ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));\r
772db4bb 509\r
510 IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;\r
687a2e5f 511 CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));\r
772db4bb 512 IpInstance->State = IP4_STATE_UNCONFIGED;\r
513 IpInstance->Service = IpSb;\r
514\r
e48e37fc 515 InitializeListHead (&IpInstance->Link);\r
772db4bb 516 NetMapInit (&IpInstance->RxTokens);\r
517 NetMapInit (&IpInstance->TxTokens);\r
e48e37fc 518 InitializeListHead (&IpInstance->Received);\r
519 InitializeListHead (&IpInstance->Delivered);\r
520 InitializeListHead (&IpInstance->AddrLink);\r
772db4bb 521\r
e48e37fc 522 EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);\r
772db4bb 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
544EFI_STATUS\r
545Ip4ConfigProtocol (\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
687a2e5f 572 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
772db4bb 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
e48e37fc 591 CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));\r
592 CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));\r
772db4bb 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
e48e37fc 623 InsertTailList (&IpSb->Interfaces, &IpIf->Link);\r
772db4bb 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
e48e37fc 659 InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);\r
772db4bb 660\r
687a2e5f 661 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
772db4bb 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
675ON_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
691EFI_STATUS\r
692Ip4CleanProtocol (\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
e48e37fc 709 if (!IsListEmpty (&IpInstance->Delivered)) {\r
772db4bb 710 ;\r
711 }\r
712\r
713 if (IpInstance->Interface != NULL) {\r
e48e37fc 714 RemoveEntryList (&IpInstance->AddrLink);\r
772db4bb 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
e48e37fc 729 gBS->FreePool (IpInstance->EfiRouteTable);\r
772db4bb 730 IpInstance->EfiRouteTable = NULL;\r
731 IpInstance->EfiRouteCount = 0;\r
732 }\r
733\r
734 if (IpInstance->Groups != NULL) {\r
e48e37fc 735 gBS->FreePool (IpInstance->Groups);\r
772db4bb 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
760BOOLEAN\r
761Ip4StationAddressValid (\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
2a86ff1c 798 NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];\r
772db4bb 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
772db4bb 823EFI_STATUS\r
824EFIAPI\r
825EfiIp4Configure (\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
e48e37fc 846 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
e48e37fc 861 CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));\r
862 CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));\r
772db4bb 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
84b5c78e 893 (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||\r
894 !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {\r
772db4bb 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
935ON_EXIT:\r
e48e37fc 936 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
957EFI_STATUS\r
958Ip4Groups (\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
e48e37fc 974 CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));\r
772db4bb 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
e48e37fc 989 gBS->FreePool (Members);\r
772db4bb 990 return EFI_DEVICE_ERROR;\r
991 }\r
992\r
993 if (IpInstance->Groups != NULL) {\r
e48e37fc 994 gBS->FreePool (IpInstance->Groups);\r
772db4bb 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
84b5c78e 1011 if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {\r
772db4bb 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
e48e37fc 1022 gBS->FreePool (IpInstance->Groups);\r
772db4bb 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
772db4bb 1051EFI_STATUS\r
1052EFIAPI\r
1053EfiIp4Groups (\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
e48e37fc 1069 CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));\r
772db4bb 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
e48e37fc 1077 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
1091ON_EXIT:\r
e48e37fc 1092 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
772db4bb 1112EFI_STATUS\r
1113EFIAPI\r
1114EfiIp4Routes (\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
e48e37fc 1139 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
e48e37fc 1151 CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));\r
1152 CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));\r
1153 CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));\r
772db4bb 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
1183ON_EXIT:\r
e48e37fc 1184 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
772db4bb 1203EFI_STATUS\r
1204Ip4TokenExist (\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
772db4bb 1235EFI_STATUS\r
1236Ip4TxTokenValid (\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
e48e37fc 1298 CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
1299 CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
772db4bb 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
772db4bb 1362VOID\r
1363Ip4FreeTxToken (\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
36ee91ca 1384\r
1385 //\r
1386 // Dispatch the DPC queued by the NotifyFunction of Token->Event.\r
1387 //\r
1388 NetLibDispatchDpc ();\r
772db4bb 1389 }\r
1390\r
e48e37fc 1391 gBS->FreePool (Wrap);\r
772db4bb 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
772db4bb 1407VOID\r
1408Ip4OnPacketSent (\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
772db4bb 1453EFI_STATUS\r
1454EFIAPI\r
1455EfiIp4Transmit (\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
e48e37fc 1484 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
e48e37fc 1518 CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));\r
772db4bb 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
e48e37fc 1528 CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
1529 CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
772db4bb 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
e48e37fc 1558 Wrap = AllocatePool (sizeof (IP4_TXTOKEN_WRAP));\r
772db4bb 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
e48e37fc 1577 gBS->FreePool (Wrap);\r
772db4bb 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
36ee91ca 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
772db4bb 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
36ee91ca 1612 Wrap->Sent = FALSE;\r
772db4bb 1613 NetbufFree (Wrap->Packet);\r
772db4bb 1614 }\r
1615\r
772db4bb 1616ON_EXIT:\r
e48e37fc 1617 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
772db4bb 1638EFI_STATUS\r
1639EFIAPI\r
1640EfiIp4Receive (\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
772db4bb 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
e48e37fc 1658 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
772db4bb 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
36ee91ca 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
772db4bb 1692ON_EXIT:\r
e48e37fc 1693 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
772db4bb 1715EFI_STATUS\r
1716Ip4CancelTxTokens (\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
772db4bb 1770EFI_STATUS\r
1771Ip4CancelRxTokens (\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
1814EFI_STATUS\r
1815Ip4Cancel (\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
36ee91ca 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
772db4bb 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
772db4bb 1892EFI_STATUS\r
1893EFIAPI\r
1894EfiIp4Cancel (\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
e48e37fc 1909 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
1923ON_EXIT:\r
e48e37fc 1924 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
772db4bb 1939EFI_STATUS\r
1940EFIAPI\r
1941EfiIp4Poll (\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
1967EFI_IP4_PROTOCOL\r
1968mEfiIp4ProtocolTemplete = {\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
1994EFI_STATUS\r
1995Ip4SentPacketTicking (\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
2026VOID\r
2027EFIAPI\r
2028Ip4TimerTicking (\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