025bcdb5a7e942ad6a4ef1dd22435bf80c2dc3b7
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   IpIo.c\r
15 \r
16 Abstract:\r
17 \r
18   The implementation of the IpIo layer.\r
19 \r
20 \r
21 **/\r
22 \r
23 #include <PiDxe.h>\r
24 \r
25 #include <Protocol/Udp4.h>\r
26 \r
27 #include <Library/IpIoLib.h>\r
28 #include <Library/BaseLib.h>\r
29 #include <Library/DebugLib.h>\r
30 #include <Library/UefiBootServicesTableLib.h>\r
31 #include <Library/MemoryAllocationLib.h>\r
32 #include <Library/BaseMemoryLib.h>\r
33 \r
34 \r
35 #define NET_PROTO_HDR(Buf, Type)  ((Type *) ((Buf)->BlockOp[0].Head))\r
36 #define ICMP_ERRLEN(IpHdr) \\r
37   (sizeof(IP4_ICMP_HEAD) + EFI_IP4_HEADER_LEN(IpHdr) + 8)\r
38 \r
39 LIST_ENTRY  mActiveIpIoList = {\r
40   &mActiveIpIoList,\r
41   &mActiveIpIoList\r
42 };\r
43 \r
44 EFI_IP4_CONFIG_DATA  mIpIoDefaultIpConfigData = {\r
45   EFI_IP_PROTO_UDP,\r
46   FALSE,\r
47   TRUE,\r
48   FALSE,\r
49   FALSE,\r
50   FALSE,\r
51   {{0, 0, 0, 0}},\r
52   {{0, 0, 0, 0}},\r
53   0,\r
54   255,\r
55   FALSE,\r
56   FALSE,\r
57   0,\r
58   0\r
59 };\r
60 \r
61 STATIC ICMP_ERROR_INFO  mIcmpErrMap[10] = {\r
62   {FALSE, TRUE},\r
63   {FALSE, TRUE},\r
64   {TRUE, TRUE},\r
65   {TRUE, TRUE},\r
66   {TRUE, TRUE},\r
67   {FALSE, TRUE},\r
68   {FALSE, TRUE},\r
69   {FALSE, TRUE},\r
70   {FALSE, FALSE},\r
71   {FALSE, TRUE}\r
72 };\r
73 \r
74 STATIC\r
75 VOID\r
76 EFIAPI\r
77 IpIoTransmitHandlerDpc (\r
78   IN VOID      *Context\r
79   );\r
80 \r
81 STATIC\r
82 VOID\r
83 EFIAPI\r
84 IpIoTransmitHandler (\r
85   IN EFI_EVENT Event,\r
86   IN VOID      *Context\r
87   );\r
88 \r
89 \r
90 /**\r
91   This function create an ip child ,open the IP protocol, return the opened\r
92   Ip protocol to Interface.\r
93 \r
94   @param  ControllerHandle      The controller handle.\r
95   @param  ImageHandle           The image handle.\r
96   @param  ChildHandle           Pointer to the buffer to save the ip child handle.\r
97   @param  Interface             Pointer used to get the ip protocol interface.\r
98 \r
99   @retval EFI_SUCCESS           The ip child is created and the ip protocol\r
100                                 interface is retrieved.\r
101   @retval other                 The required operation failed.\r
102 \r
103 **/\r
104 STATIC\r
105 EFI_STATUS\r
106 IpIoCreateIpChildOpenProtocol (\r
107   IN  EFI_HANDLE  ControllerHandle,\r
108   IN  EFI_HANDLE  ImageHandle,\r
109   IN  EFI_HANDLE  *ChildHandle,\r
110   OUT VOID        **Interface\r
111   )\r
112 {\r
113   EFI_STATUS  Status;\r
114 \r
115   //\r
116   // Create an ip child.\r
117   //\r
118   Status = NetLibCreateServiceChild (\r
119              ControllerHandle,\r
120              ImageHandle,\r
121              &gEfiIp4ServiceBindingProtocolGuid,\r
122              ChildHandle\r
123              );\r
124   if (EFI_ERROR (Status)) {\r
125     return Status;\r
126   }\r
127 \r
128   //\r
129   // Open the ip protocol installed on the *ChildHandle.\r
130   //\r
131   Status = gBS->OpenProtocol (\r
132                   *ChildHandle,\r
133                   &gEfiIp4ProtocolGuid,\r
134                   Interface,\r
135                   ImageHandle,\r
136                   ControllerHandle,\r
137                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
138                   );\r
139   if (EFI_ERROR (Status)) {\r
140     //\r
141     // On failure, destroy the ip child.\r
142     //\r
143     NetLibDestroyServiceChild (\r
144       ControllerHandle,\r
145       ImageHandle,\r
146       &gEfiIp4ServiceBindingProtocolGuid,\r
147       *ChildHandle\r
148       );\r
149   }\r
150 \r
151   return Status;\r
152 }\r
153 \r
154 \r
155 /**\r
156   This function close the previously openned ip protocol and destroy the ip child.\r
157 \r
158   @param  ControllerHandle      The controller handle.\r
159   @param  ImageHandle           the image handle.\r
160   @param  ChildHandle           The child handle of the ip child.\r
161 \r
162   @retval EFI_SUCCESS           The ip protocol is closed and the relevant ip child\r
163                                 is destroyed.\r
164   @retval other                 The required operation failed.\r
165 \r
166 **/\r
167 STATIC\r
168 EFI_STATUS\r
169 IpIoCloseProtocolDestroyIpChild (\r
170   IN EFI_HANDLE  ControllerHandle,\r
171   IN EFI_HANDLE  ImageHandle,\r
172   IN EFI_HANDLE  ChildHandle\r
173   )\r
174 {\r
175   EFI_STATUS  Status;\r
176 \r
177   //\r
178   // Close the previously openned ip protocol.\r
179   //\r
180   gBS->CloseProtocol (\r
181          ChildHandle,\r
182          &gEfiIp4ProtocolGuid,\r
183          ImageHandle,\r
184          ControllerHandle\r
185          );\r
186 \r
187   //\r
188   // Destroy the ip child.\r
189   //\r
190   Status = NetLibDestroyServiceChild (\r
191              ControllerHandle,\r
192              ImageHandle,\r
193              &gEfiIp4ServiceBindingProtocolGuid,\r
194              ChildHandle\r
195              );\r
196 \r
197   return Status;\r
198 }\r
199 \r
200 \r
201 /**\r
202   Handle ICMP packets.\r
203 \r
204   @param  IpIo                  Pointer to the IP_IO instance.\r
205   @param  Pkt                   Pointer to the ICMP packet.\r
206   @param  Session               Pointer to the net session of this ICMP packet.\r
207 \r
208   @retval EFI_SUCCESS           The ICMP packet is handled successfully.\r
209   @retval EFI_ABORTED           This type of ICMP packet is not supported.\r
210 \r
211 **/\r
212 STATIC\r
213 EFI_STATUS\r
214 IpIoIcmpHandler (\r
215   IN IP_IO                *IpIo,\r
216   IN NET_BUF              *Pkt,\r
217   IN EFI_NET_SESSION_DATA *Session\r
218   )\r
219 {\r
220   IP4_ICMP_ERROR_HEAD  *IcmpHdr;\r
221   EFI_IP4_HEADER       *IpHdr;\r
222   ICMP_ERROR           IcmpErr;\r
223   UINT8                *PayLoadHdr;\r
224   UINT8                Type;\r
225   UINT8                Code;\r
226   UINT32               TrimBytes;\r
227 \r
228   IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);\r
229   IpHdr   = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);\r
230 \r
231   //\r
232   // Check the ICMP packet length.\r
233   //\r
234   if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {\r
235 \r
236     return EFI_ABORTED;\r
237   }\r
238 \r
239   Type = IcmpHdr->Head.Type;\r
240   Code = IcmpHdr->Head.Code;\r
241 \r
242   //\r
243   // Analyze the ICMP Error in this ICMP pkt\r
244   //\r
245   switch (Type) {\r
246   case ICMP_TYPE_UNREACH:\r
247     switch (Code) {\r
248     case ICMP_CODE_UNREACH_NET:\r
249     case ICMP_CODE_UNREACH_HOST:\r
250     case ICMP_CODE_UNREACH_PROTOCOL:\r
251     case ICMP_CODE_UNREACH_PORT:\r
252     case ICMP_CODE_UNREACH_SRCFAIL:\r
253       IcmpErr = (ICMP_ERROR) (ICMP_ERR_UNREACH_NET + Code);\r
254 \r
255       break;\r
256 \r
257     case ICMP_CODE_UNREACH_NEEDFRAG:\r
258       IcmpErr = ICMP_ERR_MSGSIZE;\r
259 \r
260       break;\r
261 \r
262     case ICMP_CODE_UNREACH_NET_UNKNOWN:\r
263     case ICMP_CODE_UNREACH_NET_PROHIB:\r
264     case ICMP_CODE_UNREACH_TOSNET:\r
265       IcmpErr = ICMP_ERR_UNREACH_NET;\r
266 \r
267       break;\r
268 \r
269     case ICMP_CODE_UNREACH_HOST_UNKNOWN:\r
270     case ICMP_CODE_UNREACH_ISOLATED:\r
271     case ICMP_CODE_UNREACH_HOST_PROHIB:\r
272     case ICMP_CODE_UNREACH_TOSHOST:\r
273       IcmpErr = ICMP_ERR_UNREACH_HOST;\r
274 \r
275       break;\r
276 \r
277     default:\r
278       return EFI_ABORTED;\r
279 \r
280       break;\r
281     }\r
282 \r
283     break;\r
284 \r
285   case ICMP_TYPE_TIMXCEED:\r
286     if (Code > 1) {\r
287       return EFI_ABORTED;\r
288     }\r
289 \r
290     IcmpErr = (ICMP_ERROR) (Code + ICMP_ERR_TIMXCEED_INTRANS);\r
291 \r
292     break;\r
293 \r
294   case ICMP_TYPE_PARAMPROB:\r
295     if (Code > 1) {\r
296       return EFI_ABORTED;\r
297     }\r
298 \r
299     IcmpErr = ICMP_ERR_PARAMPROB;\r
300 \r
301     break;\r
302 \r
303   case ICMP_TYPE_SOURCEQUENCH:\r
304     if (Code != 0) {\r
305       return EFI_ABORTED;\r
306     }\r
307 \r
308     IcmpErr = ICMP_ERR_QUENCH;\r
309 \r
310     break;\r
311 \r
312   default:\r
313     return EFI_ABORTED;\r
314 \r
315     break;\r
316   }\r
317 \r
318   //\r
319   // Notify user the ICMP pkt only containing payload except\r
320   // IP and ICMP header\r
321   //\r
322   PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));\r
323   TrimBytes  = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);\r
324 \r
325   NetbufTrim (Pkt, TrimBytes, TRUE);\r
326 \r
327   IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);\r
328 \r
329   return EFI_SUCCESS;\r
330 }\r
331 \r
332 \r
333 /**\r
334   Ext free function for net buffer. This function is\r
335   called when the net buffer is freed. It is used to\r
336   signal the recycle event to notify IP to recycle the\r
337   data buffer.\r
338 \r
339   @param  Event                 The event to be signaled.\r
340 \r
341   @return None.\r
342 \r
343 **/\r
344 STATIC\r
345 VOID\r
346 IpIoExtFree (\r
347   IN VOID  *Event\r
348   )\r
349 {\r
350   gBS->SignalEvent ((EFI_EVENT) Event);\r
351 }\r
352 \r
353 \r
354 /**\r
355   Create a send entry to wrap a packet before sending\r
356   out it through IP.\r
357 \r
358   @param  IpIo                  Pointer to the IP_IO instance.\r
359   @param  Pkt                   Pointer to the packet.\r
360   @param  Sender                Pointer to the IP sender.\r
361   @param  NotifyData            Pointer to the notify data.\r
362   @param  Dest                  Pointer to the destination IP address.\r
363   @param  Override              Pointer to the overriden IP_IO data.\r
364 \r
365   @return Pointer to the data structure created to wrap the packet. If NULL,\r
366   @return resource limit occurred.\r
367 \r
368 **/\r
369 STATIC\r
370 IP_IO_SEND_ENTRY *\r
371 IpIoCreateSndEntry (\r
372   IN IP_IO             *IpIo,\r
373   IN NET_BUF           *Pkt,\r
374   IN EFI_IP4_PROTOCOL  *Sender,\r
375   IN VOID              *Context    OPTIONAL,\r
376   IN VOID              *NotifyData OPTIONAL,\r
377   IN IP4_ADDR          Dest,\r
378   IN IP_IO_OVERRIDE    *Override\r
379   )\r
380 {\r
381   IP_IO_SEND_ENTRY          *SndEntry;\r
382   EFI_IP4_COMPLETION_TOKEN  *SndToken;\r
383   EFI_IP4_TRANSMIT_DATA     *TxData;\r
384   EFI_STATUS                Status;\r
385   EFI_IP4_OVERRIDE_DATA     *OverrideData;\r
386   volatile UINT32           Index;\r
387 \r
388   //\r
389   // Allocate resource for SndEntry\r
390   //\r
391   SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));\r
392   if (NULL == SndEntry) {\r
393     return NULL;\r
394   }\r
395 \r
396   //\r
397   // Allocate resource for SndToken\r
398   //\r
399   SndToken = AllocatePool (sizeof (EFI_IP4_COMPLETION_TOKEN));\r
400   if (NULL == SndToken) {\r
401     goto ReleaseSndEntry;\r
402   }\r
403 \r
404   Status = gBS->CreateEvent (\r
405                   EVT_NOTIFY_SIGNAL,\r
406                   TPL_NOTIFY,\r
407                   IpIoTransmitHandler,\r
408                   SndEntry,\r
409                   &(SndToken->Event)\r
410                   );\r
411   if (EFI_ERROR (Status)) {\r
412     goto ReleaseSndToken;\r
413   }\r
414 \r
415   //\r
416   // Allocate resource for TxData\r
417   //\r
418   TxData = AllocatePool (\r
419     sizeof (EFI_IP4_TRANSMIT_DATA) +\r
420     sizeof (EFI_IP4_FRAGMENT_DATA) * (Pkt->BlockOpNum - 1)\r
421     );\r
422 \r
423   if (NULL == TxData) {\r
424     goto ReleaseEvent;\r
425   }\r
426 \r
427   //\r
428   // Allocate resource for OverrideData if needed\r
429   //\r
430   OverrideData = NULL;\r
431   if (NULL != Override) {\r
432 \r
433     OverrideData = AllocatePool (sizeof (EFI_IP4_OVERRIDE_DATA));\r
434     if (NULL == OverrideData) {\r
435       goto ReleaseResource;\r
436     }\r
437     //\r
438     // Set the fields of OverrideData\r
439     //\r
440     CopyMem (OverrideData, Override, sizeof (*OverrideData));\r
441   }\r
442 \r
443   //\r
444   // Set the fields of TxData\r
445   //\r
446   CopyMem (&TxData->DestinationAddress, &Dest, sizeof (EFI_IPv4_ADDRESS));\r
447   TxData->OverrideData                  = OverrideData;\r
448   TxData->OptionsLength                 = 0;\r
449   TxData->OptionsBuffer                 = NULL;\r
450   TxData->TotalDataLength               = Pkt->TotalSize;\r
451   TxData->FragmentCount                 = Pkt->BlockOpNum;\r
452 \r
453 \r
454   for (Index = 0; Index < Pkt->BlockOpNum; Index++) {\r
455     TxData->FragmentTable[Index].FragmentBuffer = Pkt->BlockOp[Index].Head;\r
456     TxData->FragmentTable[Index].FragmentLength = Pkt->BlockOp[Index].Size;\r
457   }\r
458 \r
459   //\r
460   // Set the fields of SndToken\r
461   //\r
462   SndToken->Packet.TxData = TxData;\r
463 \r
464   //\r
465   // Set the fields of SndEntry\r
466   //\r
467   SndEntry->IpIo        = IpIo;\r
468   SndEntry->Ip      = Sender;\r
469   SndEntry->Context     = Context;\r
470   SndEntry->NotifyData  = NotifyData;\r
471 \r
472   SndEntry->Pkt         = Pkt;\r
473   NET_GET_REF (Pkt);\r
474 \r
475   SndEntry->SndToken = SndToken;\r
476 \r
477   InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);\r
478 \r
479   return SndEntry;\r
480 \r
481 ReleaseResource:\r
482   gBS->FreePool (TxData);\r
483 \r
484 ReleaseEvent:\r
485   gBS->CloseEvent (SndToken->Event);\r
486 \r
487 ReleaseSndToken:\r
488   gBS->FreePool (SndToken);\r
489 \r
490 ReleaseSndEntry:\r
491   gBS->FreePool (SndEntry);\r
492 \r
493   return NULL;\r
494 }\r
495 \r
496 \r
497 /**\r
498   Destroy the SndEntry.\r
499 \r
500   @param  SndEntry              Pointer to the send entry to be destroyed.\r
501 \r
502   @return None.\r
503 \r
504 **/\r
505 STATIC\r
506 VOID\r
507 IpIoDestroySndEntry (\r
508   IN IP_IO_SEND_ENTRY  *SndEntry\r
509   )\r
510 {\r
511   EFI_IP4_TRANSMIT_DATA  *TxData;\r
512 \r
513   TxData = SndEntry->SndToken->Packet.TxData;\r
514 \r
515   if (NULL != TxData->OverrideData) {\r
516     gBS->FreePool (TxData->OverrideData);\r
517   }\r
518 \r
519   gBS->FreePool (TxData);\r
520   NetbufFree (SndEntry->Pkt);\r
521   gBS->CloseEvent (SndEntry->SndToken->Event);\r
522 \r
523   gBS->FreePool (SndEntry->SndToken);\r
524   RemoveEntryList (&SndEntry->Entry);\r
525 \r
526   gBS->FreePool (SndEntry);\r
527 }\r
528 \r
529 \r
530 /**\r
531   Notify function for IP transmit token.\r
532 \r
533   @param  Context               The context passed in by the event notifier.\r
534 \r
535   @return None.\r
536 \r
537 **/\r
538 STATIC\r
539 VOID\r
540 EFIAPI\r
541 IpIoTransmitHandlerDpc (\r
542   IN VOID      *Context\r
543   )\r
544 {\r
545   IP_IO             *IpIo;\r
546   IP_IO_SEND_ENTRY  *SndEntry;\r
547 \r
548   SndEntry  = (IP_IO_SEND_ENTRY *) Context;\r
549 \r
550   IpIo      = SndEntry->IpIo;\r
551 \r
552   if (IpIo->PktSentNotify && SndEntry->NotifyData) {\r
553     IpIo->PktSentNotify (\r
554             SndEntry->SndToken->Status,\r
555             SndEntry->Context,\r
556             SndEntry->Ip,\r
557             SndEntry->NotifyData\r
558             );\r
559   }\r
560 \r
561   IpIoDestroySndEntry (SndEntry);\r
562 }\r
563 \r
564 /**\r
565   Notify function for IP transmit token.\r
566 \r
567   @param  Event                 The event signaled.\r
568   @param  Context               The context passed in by the event notifier.\r
569 \r
570   @return None.\r
571 \r
572 **/\r
573 \r
574 STATIC\r
575 VOID\r
576 EFIAPI\r
577 IpIoTransmitHandler (\r
578   IN EFI_EVENT Event,\r
579   IN VOID      *Context\r
580   )\r
581 {\r
582   //\r
583   // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK\r
584   //\r
585   NetLibQueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);\r
586 }\r
587 \r
588 \r
589 /**\r
590   The dummy handler for the dummy IP receive token.\r
591 \r
592   @param  Context               The context passed in by the event notifier.\r
593 \r
594   @return None.\r
595 \r
596 **/\r
597 STATIC\r
598 VOID\r
599 EFIAPI\r
600 IpIoDummyHandlerDpc (\r
601   IN VOID      *Context\r
602   )\r
603 {\r
604   IP_IO_IP_INFO             *IpInfo;\r
605   EFI_IP4_COMPLETION_TOKEN  *DummyToken;\r
606 \r
607   IpInfo      = (IP_IO_IP_INFO *) Context;\r
608   DummyToken  = &(IpInfo->DummyRcvToken);\r
609 \r
610   if (EFI_ABORTED == DummyToken->Status) {\r
611     //\r
612     // The reception is actively aborted by the consumer, directly return.\r
613     //\r
614     return;\r
615   } else if (EFI_SUCCESS == DummyToken->Status) {\r
616     ASSERT (DummyToken->Packet.RxData);\r
617 \r
618     gBS->SignalEvent (DummyToken->Packet.RxData->RecycleSignal);\r
619   }\r
620 \r
621   IpInfo->Ip->Receive (IpInfo->Ip, DummyToken);\r
622 }\r
623 \r
624 \r
625 /**\r
626   Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK.\r
627 \r
628   @param  Event                 The event signaled.\r
629   @param  Context               The context passed in by the event notifier.\r
630 \r
631   @return None.\r
632 \r
633 **/\r
634 STATIC\r
635 VOID\r
636 EFIAPI\r
637 IpIoDummyHandler (\r
638   IN EFI_EVENT Event,\r
639   IN VOID      *Context\r
640   )\r
641 {\r
642   //\r
643   // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK\r
644   //\r
645   NetLibQueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);\r
646 }\r
647 \r
648 \r
649 /**\r
650   Notify function for the IP receive token, used to process\r
651   the received IP packets.\r
652 \r
653   @param  Context               The context passed in by the event notifier.\r
654 \r
655   @return None.\r
656 \r
657 **/\r
658 STATIC\r
659 VOID\r
660 EFIAPI\r
661 IpIoListenHandlerDpc (\r
662   IN VOID      *Context\r
663   )\r
664 {\r
665   IP_IO                 *IpIo;\r
666   EFI_STATUS            Status;\r
667   EFI_IP4_RECEIVE_DATA  *RxData;\r
668   EFI_IP4_PROTOCOL      *Ip;\r
669   EFI_NET_SESSION_DATA  Session;\r
670   NET_BUF               *Pkt;\r
671 \r
672   IpIo    = (IP_IO *) Context;\r
673 \r
674   Ip      = IpIo->Ip;\r
675   Status  = IpIo->RcvToken.Status;\r
676   RxData  = IpIo->RcvToken.Packet.RxData;\r
677 \r
678   if (EFI_ABORTED == Status) {\r
679     //\r
680     // The reception is actively aborted by the consumer, directly return.\r
681     //\r
682     return;\r
683   }\r
684 \r
685   if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {\r
686     //\r
687     // Only process the normal packets and the icmp error packets, if RxData is NULL\r
688     // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although\r
689     // this should be a bug of the low layer (IP).\r
690     //\r
691     goto Resume;\r
692   }\r
693 \r
694   if (NULL == IpIo->PktRcvdNotify) {\r
695     goto CleanUp;\r
696   }\r
697 \r
698   if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&\r
699     !Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {\r
700     //\r
701     // The source address is not zero and it's not a unicast IP address, discard it.\r
702     //\r
703     goto CleanUp;\r
704   }\r
705 \r
706   //\r
707   // Create a netbuffer representing packet\r
708   //\r
709   Pkt = NetbufFromExt (\r
710           (NET_FRAGMENT *) RxData->FragmentTable,\r
711           RxData->FragmentCount,\r
712           0,\r
713           0,\r
714           IpIoExtFree,\r
715           RxData->RecycleSignal\r
716           );\r
717   if (NULL == Pkt) {\r
718     goto CleanUp;\r
719   }\r
720 \r
721   //\r
722   // Create a net session\r
723   //\r
724   Session.Source = EFI_IP4 (RxData->Header->SourceAddress);\r
725   Session.Dest   = EFI_IP4 (RxData->Header->DestinationAddress);\r
726   Session.IpHdr  = RxData->Header;\r
727 \r
728   if (EFI_SUCCESS == Status) {\r
729 \r
730     IpIo->PktRcvdNotify (EFI_SUCCESS, (ICMP_ERROR) 0, &Session, Pkt, IpIo->RcvdContext);\r
731   } else {\r
732     //\r
733     // Status is EFI_ICMP_ERROR\r
734     //\r
735     Status = IpIoIcmpHandler (IpIo, Pkt, &Session);\r
736     if (EFI_ERROR (Status)) {\r
737       NetbufFree (Pkt);\r
738     }\r
739   }\r
740 \r
741   goto Resume;\r
742 \r
743 CleanUp:\r
744   gBS->SignalEvent (RxData->RecycleSignal);\r
745 \r
746 Resume:\r
747   Ip->Receive (Ip, &(IpIo->RcvToken));\r
748 }\r
749 \r
750 \r
751 /**\r
752   Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
753 \r
754   @param  Event                 The event signaled.\r
755   @param  Context               The context passed in by the event notifier.\r
756 \r
757   @return None.\r
758 \r
759 **/\r
760 STATIC\r
761 VOID\r
762 EFIAPI\r
763 IpIoListenHandler (\r
764   IN EFI_EVENT Event,\r
765   IN VOID      *Context\r
766   )\r
767 {\r
768   //\r
769   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
770   //\r
771   NetLibQueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);\r
772 }\r
773 \r
774 \r
775 /**\r
776   Create a new IP_IO instance.\r
777 \r
778   @param  Image                 The image handle of an IP_IO consumer protocol.\r
779   @param  Controller            The controller handle of an IP_IO consumer protocol\r
780                                 installed on.\r
781 \r
782   @return Pointer to a newly created IP_IO instance.\r
783 \r
784 **/\r
785 IP_IO *\r
786 EFIAPI\r
787 IpIoCreate (\r
788   IN EFI_HANDLE Image,\r
789   IN EFI_HANDLE Controller\r
790   )\r
791 {\r
792   EFI_STATUS  Status;\r
793   IP_IO       *IpIo;\r
794 \r
795   IpIo = AllocateZeroPool (sizeof (IP_IO));\r
796   if (NULL == IpIo) {\r
797     return NULL;\r
798   }\r
799 \r
800   InitializeListHead (&(IpIo->PendingSndList));\r
801   InitializeListHead (&(IpIo->IpList));\r
802   IpIo->Controller  = Controller;\r
803   IpIo->Image       = Image;\r
804 \r
805   Status = gBS->CreateEvent (\r
806                   EVT_NOTIFY_SIGNAL,\r
807                   TPL_NOTIFY,\r
808                   IpIoListenHandler,\r
809                   IpIo,\r
810                   &(IpIo->RcvToken.Event)\r
811                   );\r
812   if (EFI_ERROR (Status)) {\r
813     goto ReleaseIpIo;\r
814   }\r
815 \r
816   //\r
817   // Create an IP child and open IP protocol\r
818   //\r
819   Status = IpIoCreateIpChildOpenProtocol (\r
820              Controller,\r
821              Image,\r
822              &IpIo->ChildHandle,\r
823              (VOID **)&(IpIo->Ip)\r
824              );\r
825   if (EFI_ERROR (Status)) {\r
826     goto ReleaseIpIo;\r
827   }\r
828 \r
829   return IpIo;\r
830 \r
831 ReleaseIpIo:\r
832 \r
833   if (NULL != IpIo->RcvToken.Event) {\r
834     gBS->CloseEvent (IpIo->RcvToken.Event);\r
835   }\r
836 \r
837   gBS->FreePool (IpIo);\r
838 \r
839   return NULL;\r
840 }\r
841 \r
842 \r
843 /**\r
844   Open an IP_IO instance for use.\r
845 \r
846   @param  IpIo                  Pointer to an IP_IO instance that needs to open.\r
847   @param  OpenData              The configuration data for the IP_IO instance.\r
848 \r
849   @retval EFI_SUCCESS           The IP_IO instance opened with OpenData\r
850                                 successfully.\r
851   @retval other                 Error condition occurred.\r
852 \r
853 **/\r
854 EFI_STATUS\r
855 EFIAPI\r
856 IpIoOpen (\r
857   IN IP_IO           *IpIo,\r
858   IN IP_IO_OPEN_DATA *OpenData\r
859   )\r
860 {\r
861   EFI_STATUS        Status;\r
862   EFI_IP4_PROTOCOL  *Ip;\r
863 \r
864   if (IpIo->IsConfigured) {\r
865     return EFI_ACCESS_DENIED;\r
866   }\r
867 \r
868   Ip = IpIo->Ip;\r
869 \r
870   //\r
871   // configure ip\r
872   //\r
873   Status = Ip->Configure (Ip, &OpenData->IpConfigData);\r
874   if (EFI_ERROR (Status)) {\r
875     return Status;\r
876   }\r
877 \r
878   //\r
879   // bugbug: to delete the default route entry in this Ip, if it is:\r
880   // (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified\r
881   // its code\r
882   //\r
883   Status = Ip->Routes (Ip, TRUE, &mZeroIp4Addr, &mZeroIp4Addr, &mZeroIp4Addr);\r
884 \r
885   if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {\r
886     return Status;\r
887   }\r
888 \r
889   IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;\r
890   IpIo->PktSentNotify = OpenData->PktSentNotify;\r
891 \r
892   IpIo->RcvdContext   = OpenData->RcvdContext;\r
893   IpIo->SndContext    = OpenData->SndContext;\r
894 \r
895   IpIo->Protocol      = OpenData->IpConfigData.DefaultProtocol;\r
896 \r
897   //\r
898   // start to listen incoming packet\r
899   //\r
900   Status = Ip->Receive (Ip, &(IpIo->RcvToken));\r
901   if (EFI_ERROR (Status)) {\r
902     Ip->Configure (Ip, NULL);\r
903     goto ErrorExit;\r
904   }\r
905 \r
906   IpIo->IsConfigured = TRUE;\r
907   InsertTailList (&mActiveIpIoList, &IpIo->Entry);\r
908 \r
909 ErrorExit:\r
910 \r
911   return Status;\r
912 }\r
913 \r
914 \r
915 /**\r
916   Stop an IP_IO instance.\r
917 \r
918   @param  IpIo                  Pointer to the IP_IO instance that needs to stop.\r
919 \r
920   @retval EFI_SUCCESS           The IP_IO instance stopped successfully.\r
921   @retval other                 Error condition occurred.\r
922 \r
923 **/\r
924 EFI_STATUS\r
925 IpIoStop (\r
926   IN IP_IO *IpIo\r
927   )\r
928 {\r
929   EFI_STATUS        Status;\r
930   EFI_IP4_PROTOCOL  *Ip;\r
931   IP_IO_IP_INFO     *IpInfo;\r
932 \r
933   if (!IpIo->IsConfigured) {\r
934     return EFI_SUCCESS;\r
935   }\r
936 \r
937   //\r
938   // Remove the IpIo from the active IpIo list.\r
939   //\r
940   RemoveEntryList (&IpIo->Entry);\r
941 \r
942   Ip = IpIo->Ip;\r
943 \r
944   //\r
945   // Configure NULL Ip\r
946   //\r
947   Status = Ip->Configure (Ip, NULL);\r
948   if (EFI_ERROR (Status)) {\r
949     return Status;\r
950   }\r
951 \r
952   IpIo->IsConfigured = FALSE;\r
953 \r
954   //\r
955   // Detroy the Ip List used by IpIo\r
956   //\r
957 \r
958   while (!IsListEmpty (&(IpIo->IpList))) {\r
959     IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);\r
960 \r
961     IpIoRemoveIp (IpIo, IpInfo);\r
962   }\r
963 \r
964   //\r
965   // All pending snd tokens should be flushed by reseting the IP instances.\r
966   //\r
967   ASSERT (IsListEmpty (&IpIo->PendingSndList));\r
968 \r
969   //\r
970   // Close the receive event.\r
971   //\r
972   gBS->CloseEvent (IpIo->RcvToken.Event);\r
973 \r
974   return EFI_SUCCESS;\r
975 }\r
976 \r
977 \r
978 /**\r
979   Destroy an IP_IO instance.\r
980 \r
981   @param  IpIo                  Pointer to the IP_IO instance that needs to\r
982                                 destroy.\r
983 \r
984   @retval EFI_SUCCESS           The IP_IO instance destroyed successfully.\r
985   @retval other                 Error condition occurred.\r
986 \r
987 **/\r
988 EFI_STATUS\r
989 EFIAPI\r
990 IpIoDestroy (\r
991   IN IP_IO *IpIo\r
992   )\r
993 {\r
994   //\r
995   // Stop the IpIo.\r
996   //\r
997   IpIoStop (IpIo);\r
998 \r
999   //\r
1000   // Close the IP protocol and destroy the child.\r
1001   //\r
1002   IpIoCloseProtocolDestroyIpChild (IpIo->Controller, IpIo->Image, IpIo->ChildHandle);\r
1003 \r
1004   gBS->FreePool (IpIo);\r
1005 \r
1006   return EFI_SUCCESS;\r
1007 }\r
1008 \r
1009 \r
1010 /**\r
1011   Send out an IP packet.\r
1012 \r
1013   @param  IpIo                  Pointer to an IP_IO instance used for sending IP\r
1014                                 packet.\r
1015   @param  Pkt                   Pointer to the IP packet to be sent.\r
1016   @param  Sender                The IP protocol instance used for sending.\r
1017   @param  NotifyData\r
1018   @param  Dest                  The destination IP address to send this packet to.\r
1019   @param  OverrideData          The data to override some configuration of the IP\r
1020                                 instance used for sending.\r
1021 \r
1022   @retval EFI_SUCCESS           The operation is completed successfully.\r
1023   @retval EFI_NOT_STARTED       The IpIo is not configured.\r
1024   @retval EFI_OUT_OF_RESOURCES  Failed due to resource limit.\r
1025 \r
1026 **/\r
1027 EFI_STATUS\r
1028 EFIAPI\r
1029 IpIoSend (\r
1030   IN IP_IO           *IpIo,\r
1031   IN NET_BUF         *Pkt,\r
1032   IN IP_IO_IP_INFO   *Sender,\r
1033   IN VOID            *Context    OPTIONAL,\r
1034   IN VOID            *NotifyData OPTIONAL,\r
1035   IN IP4_ADDR        Dest,\r
1036   IN IP_IO_OVERRIDE  *OverrideData\r
1037   )\r
1038 {\r
1039   EFI_STATUS        Status;\r
1040   EFI_IP4_PROTOCOL  *Ip;\r
1041   IP_IO_SEND_ENTRY  *SndEntry;\r
1042 \r
1043   if (!IpIo->IsConfigured) {\r
1044     return EFI_NOT_STARTED;\r
1045   }\r
1046 \r
1047   Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;\r
1048 \r
1049   //\r
1050   // create a new SndEntry\r
1051   //\r
1052   SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);\r
1053   if (NULL == SndEntry) {\r
1054     return EFI_OUT_OF_RESOURCES;\r
1055   }\r
1056 \r
1057   //\r
1058   // Send this Packet\r
1059   //\r
1060   Status = Ip->Transmit (Ip, SndEntry->SndToken);\r
1061   if (EFI_ERROR (Status)) {\r
1062     IpIoDestroySndEntry (SndEntry);\r
1063   }\r
1064 \r
1065   return Status;\r
1066 }\r
1067 \r
1068 \r
1069 /**\r
1070   Cancel the IP transmit token which wraps this Packet.\r
1071 \r
1072   @param  IpIo                  Pointer to the IP_IO instance.\r
1073   @param  Packet                Pointer to the packet to cancel.\r
1074 \r
1075   @return N/A.\r
1076 \r
1077 **/\r
1078 VOID\r
1079 EFIAPI\r
1080 IpIoCancelTxToken (\r
1081   IN IP_IO  *IpIo,\r
1082   IN VOID   *Packet\r
1083   )\r
1084 {\r
1085   LIST_ENTRY        *Node;\r
1086   IP_IO_SEND_ENTRY  *SndEntry;\r
1087   EFI_IP4_PROTOCOL  *Ip;\r
1088 \r
1089   ASSERT (IpIo && Packet);\r
1090 \r
1091   NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {\r
1092 \r
1093     SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);\r
1094 \r
1095     if (SndEntry->Pkt == Packet) {\r
1096 \r
1097       Ip = SndEntry->Ip;\r
1098       Ip->Cancel (Ip, SndEntry->SndToken);\r
1099 \r
1100       break;\r
1101     }\r
1102   }\r
1103 \r
1104 }\r
1105 \r
1106 \r
1107 /**\r
1108   Add a new IP instance for sending data.\r
1109 \r
1110   @param  IpIo                  Pointer to a IP_IO instance to add a new IP\r
1111                                 instance for sending purpose.\r
1112 \r
1113   @return Pointer to the created IP_IO_IP_INFO structure, NULL is failed.\r
1114 \r
1115 **/\r
1116 IP_IO_IP_INFO *\r
1117 EFIAPI\r
1118 IpIoAddIp (\r
1119   IN IP_IO  *IpIo\r
1120   )\r
1121 {\r
1122   EFI_STATUS     Status;\r
1123   IP_IO_IP_INFO  *IpInfo;\r
1124 \r
1125   ASSERT (IpIo);\r
1126 \r
1127   IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));\r
1128   if (IpInfo == NULL) {\r
1129     return IpInfo;\r
1130   }\r
1131 \r
1132   //\r
1133   // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP\r
1134   // instance.\r
1135   //\r
1136   InitializeListHead (&IpInfo->Entry);\r
1137   IpInfo->ChildHandle = NULL;\r
1138   IpInfo->Addr        = 0;\r
1139   IpInfo->SubnetMask  = 0;\r
1140   IpInfo->RefCnt      = 1;\r
1141 \r
1142   //\r
1143   // Create the IP instance and open the Ip4 protocol.\r
1144   //\r
1145   Status = IpIoCreateIpChildOpenProtocol (\r
1146              IpIo->Controller,\r
1147              IpIo->Image,\r
1148              &IpInfo->ChildHandle,\r
1149              (VOID **) &IpInfo->Ip\r
1150              );\r
1151   if (EFI_ERROR (Status)) {\r
1152     goto ReleaseIpInfo;\r
1153   }\r
1154 \r
1155   //\r
1156   // Create the event for the DummyRcvToken.\r
1157   //\r
1158   Status = gBS->CreateEvent (\r
1159                   EVT_NOTIFY_SIGNAL,\r
1160                   TPL_NOTIFY,\r
1161                   IpIoDummyHandler,\r
1162                   IpInfo,\r
1163                   &IpInfo->DummyRcvToken.Event\r
1164                   );\r
1165   if (EFI_ERROR (Status)) {\r
1166     goto ReleaseIpChild;\r
1167   }\r
1168 \r
1169   //\r
1170   // Link this IpInfo into the IpIo.\r
1171   //\r
1172   InsertTailList (&IpIo->IpList, &IpInfo->Entry);\r
1173 \r
1174   return IpInfo;\r
1175 \r
1176 ReleaseIpChild:\r
1177 \r
1178   IpIoCloseProtocolDestroyIpChild (\r
1179     IpIo->Controller,\r
1180     IpIo->Image,\r
1181     IpInfo->ChildHandle\r
1182     );\r
1183 \r
1184 ReleaseIpInfo:\r
1185 \r
1186   gBS->FreePool (IpInfo);\r
1187 \r
1188   return NULL;\r
1189 }\r
1190 \r
1191 \r
1192 /**\r
1193   Configure the IP instance of this IpInfo and start the receiving if Ip4ConfigData\r
1194   is not NULL.\r
1195 \r
1196   @param  IpInfo                Pointer to the IP_IO_IP_INFO instance.\r
1197   @param  Ip4ConfigData         The IP4 configure data used to configure the ip\r
1198                                 instance, if NULL the ip instance is reseted. If\r
1199                                 UseDefaultAddress is set to TRUE, and the configure\r
1200                                 operation succeeds, the default address information\r
1201                                 is written back in this Ip4ConfigData.\r
1202 \r
1203   @retval EFI_STATUS            The status returned by IP4->Configure or\r
1204                                 IP4->Receive.\r
1205 \r
1206 **/\r
1207 EFI_STATUS\r
1208 EFIAPI\r
1209 IpIoConfigIp (\r
1210   IN     IP_IO_IP_INFO        *IpInfo,\r
1211   IN OUT EFI_IP4_CONFIG_DATA  *Ip4ConfigData OPTIONAL\r
1212   )\r
1213 {\r
1214   EFI_STATUS         Status;\r
1215   EFI_IP4_PROTOCOL   *Ip;\r
1216   EFI_IP4_MODE_DATA  Ip4ModeData;\r
1217 \r
1218   ASSERT (IpInfo);\r
1219 \r
1220   if (IpInfo->RefCnt > 1) {\r
1221     //\r
1222     // This IP instance is shared, don't reconfigure it until it has only one\r
1223     // consumer. Currently, only the tcp children cloned from their passive parent\r
1224     // will share the same IP. So this cases only happens while Ip4ConfigData is NULL,\r
1225     // let the last consumer clean the IP instance.\r
1226     //\r
1227     return EFI_SUCCESS;\r
1228   }\r
1229 \r
1230   Ip = IpInfo->Ip;\r
1231 \r
1232   Status = Ip->Configure (Ip, Ip4ConfigData);\r
1233   if (EFI_ERROR (Status)) {\r
1234     goto OnExit;\r
1235   }\r
1236 \r
1237   if (Ip4ConfigData != NULL) {\r
1238 \r
1239     if (Ip4ConfigData->UseDefaultAddress) {\r
1240       Ip->GetModeData (Ip, &Ip4ModeData, NULL, NULL);\r
1241 \r
1242       Ip4ConfigData->StationAddress = Ip4ModeData.ConfigData.StationAddress;\r
1243       Ip4ConfigData->SubnetMask     = Ip4ModeData.ConfigData.SubnetMask;\r
1244     }\r
1245 \r
1246     CopyMem (&IpInfo->Addr, &Ip4ConfigData->StationAddress, sizeof (IP4_ADDR));\r
1247     CopyMem (&IpInfo->SubnetMask, &Ip4ConfigData->SubnetMask, sizeof (IP4_ADDR));\r
1248 \r
1249     Status = Ip->Receive (Ip, &IpInfo->DummyRcvToken);\r
1250     if (EFI_ERROR (Status)) {\r
1251       Ip->Configure (Ip, NULL);\r
1252     }\r
1253   } else {\r
1254 \r
1255     //\r
1256     // The IP instance is reseted, set the stored Addr and SubnetMask to zero.\r
1257     //\r
1258     IpInfo->Addr       = 0;\r
1259     IpInfo->SubnetMask =0;\r
1260   }\r
1261 \r
1262 OnExit:\r
1263 \r
1264   return Status;\r
1265 }\r
1266 \r
1267 \r
1268 /**\r
1269   Destroy an IP instance maintained in IpIo->IpList for\r
1270   sending purpose.\r
1271 \r
1272   @param  IpIo                  Pointer to the IP_IO instance.\r
1273   @param  IpInfo                Pointer to the IpInfo to be removed.\r
1274 \r
1275   @return None.\r
1276 \r
1277 **/\r
1278 VOID\r
1279 EFIAPI\r
1280 IpIoRemoveIp (\r
1281   IN IP_IO          *IpIo,\r
1282   IN IP_IO_IP_INFO  *IpInfo\r
1283   )\r
1284 {\r
1285   ASSERT (IpInfo->RefCnt > 0);\r
1286 \r
1287   NET_PUT_REF (IpInfo);\r
1288 \r
1289   if (IpInfo->RefCnt > 0) {\r
1290 \r
1291     return;\r
1292   }\r
1293 \r
1294   RemoveEntryList (&IpInfo->Entry);\r
1295 \r
1296   IpInfo->Ip->Configure (IpInfo->Ip, NULL);\r
1297 \r
1298   IpIoCloseProtocolDestroyIpChild (IpIo->Controller, IpIo->Image, IpInfo->ChildHandle);\r
1299 \r
1300   gBS->CloseEvent (IpInfo->DummyRcvToken.Event);\r
1301 \r
1302   gBS->FreePool (IpInfo);\r
1303 }\r
1304 \r
1305 \r
1306 /**\r
1307   Find the first IP protocol maintained in IpIo whose local\r
1308   address is the same with Src.\r
1309 \r
1310   @param  IpIo                  Pointer to the pointer of the IP_IO instance.\r
1311   @param  Src                   The local IP address.\r
1312 \r
1313   @return Pointer to the IP protocol can be used for sending purpose and its local\r
1314   @return address is the same with Src.\r
1315 \r
1316 **/\r
1317 IP_IO_IP_INFO *\r
1318 EFIAPI\r
1319 IpIoFindSender (\r
1320   IN OUT IP_IO     **IpIo,\r
1321   IN     IP4_ADDR  Src\r
1322   )\r
1323 {\r
1324   LIST_ENTRY      *IpIoEntry;\r
1325   IP_IO           *IpIoPtr;\r
1326   LIST_ENTRY      *IpInfoEntry;\r
1327   IP_IO_IP_INFO   *IpInfo;\r
1328 \r
1329   NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {\r
1330     IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);\r
1331 \r
1332     if ((*IpIo != NULL) && (*IpIo != IpIoPtr)) {\r
1333       continue;\r
1334     }\r
1335 \r
1336     NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {\r
1337       IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);\r
1338 \r
1339       if (IpInfo->Addr == Src) {\r
1340         *IpIo = IpIoPtr;\r
1341         return IpInfo;\r
1342       }\r
1343     }\r
1344   }\r
1345 \r
1346   //\r
1347   // No match.\r
1348   //\r
1349   return NULL;\r
1350 }\r
1351 \r
1352 \r
1353 /**\r
1354   Get the ICMP error map information, the ErrorStatus will be returned.\r
1355   The IsHard and Notify are optional. If they are not NULL, this rouine will\r
1356   fill them.\r
1357   We move IcmpErrMap[] to local variable to enable EBC build.\r
1358 \r
1359   @param  IcmpError             IcmpError Type\r
1360   @param  IsHard                Whether it is a hard error\r
1361   @param  Notify                Whether it need to notify SockError\r
1362 \r
1363   @return ICMP Error Status\r
1364 \r
1365 **/\r
1366 EFI_STATUS\r
1367 EFIAPI\r
1368 IpIoGetIcmpErrStatus (\r
1369   IN  ICMP_ERROR  IcmpError,\r
1370   OUT BOOLEAN     *IsHard, OPTIONAL\r
1371   OUT BOOLEAN     *Notify OPTIONAL\r
1372   )\r
1373 {\r
1374   ASSERT ((IcmpError >= ICMP_ERR_UNREACH_NET) && (IcmpError <= ICMP_ERR_PARAMPROB));\r
1375 \r
1376   if (IsHard != NULL) {\r
1377     *IsHard = mIcmpErrMap[IcmpError].IsHard;\r
1378   }\r
1379 \r
1380   if (Notify != NULL) {\r
1381     *Notify = mIcmpErrMap[IcmpError].Notify;\r
1382   }\r
1383 \r
1384   switch (IcmpError) {\r
1385   case ICMP_ERR_UNREACH_NET:\r
1386     return  EFI_NETWORK_UNREACHABLE;\r
1387 \r
1388   case ICMP_ERR_TIMXCEED_INTRANS:\r
1389   case ICMP_ERR_TIMXCEED_REASS:\r
1390   case ICMP_ERR_UNREACH_HOST:\r
1391     return  EFI_HOST_UNREACHABLE;\r
1392 \r
1393   case ICMP_ERR_UNREACH_PROTOCOL:\r
1394     return  EFI_PROTOCOL_UNREACHABLE;\r
1395 \r
1396   case ICMP_ERR_UNREACH_PORT:\r
1397     return  EFI_PORT_UNREACHABLE;\r
1398 \r
1399   case ICMP_ERR_MSGSIZE:\r
1400   case ICMP_ERR_UNREACH_SRCFAIL:\r
1401   case ICMP_ERR_QUENCH:\r
1402   case ICMP_ERR_PARAMPROB:\r
1403     return  EFI_ICMP_ERROR;\r
1404   }\r
1405 \r
1406   //\r
1407   // will never run here!\r
1408   //\r
1409   ASSERT (FALSE);\r
1410   return EFI_UNSUPPORTED;\r
1411 }\r
1412 \r