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