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