1 /** @file
2   IpIo Library.
3 
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8 
9 #include <Uefi.h>
10 
11 #include <Protocol/Udp4.h>
12 
13 #include <Library/IpIoLib.h>
14 #include <Library/BaseLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/DpcLib.h>
20 
21 
22 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY  mActiveIpIoList = {
23   &mActiveIpIoList,
24   &mActiveIpIoList
25 };
26 
27 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA  mIp4IoDefaultIpConfigData = {
28   EFI_IP_PROTO_UDP,
29   FALSE,
30   TRUE,
31   FALSE,
32   FALSE,
33   FALSE,
34   {{0, 0, 0, 0}},
35   {{0, 0, 0, 0}},
36   0,
37   255,
38   FALSE,
39   FALSE,
40   0,
41   0
42 };
43 
44 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA  mIp6IoDefaultIpConfigData = {
45   EFI_IP_PROTO_UDP,
46   FALSE,
47   TRUE,
48   FALSE,
49   {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
50   {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
51   0,
52   255,
53   0,
54   0,
55   0
56 };
57 
58 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmpErrMap[10] = {
59   {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET
60   {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST
61   {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PROTOCOL
62   {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PORT
63   {TRUE,  TRUE }, // ICMP_ERR_MSGSIZE
64   {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL
65   {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS
66   {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS
67   {FALSE, FALSE}, // ICMP_ERR_QUENCH
68   {FALSE, TRUE }  // ICMP_ERR_PARAMPROB
69 };
70 
71 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmp6ErrMap[10] = {
72   {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET
73   {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST
74   {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL
75   {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PORT
76   {TRUE,  TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG
77   {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
78   {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS
79   {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER
80   {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER
81   {FALSE, TRUE}  // ICMP6_ERR_PARAMPROB_IPV6OPTION
82 };
83 
84 
85 /**
86   Notify function for IP transmit token.
87 
88   @param[in]  Context               The context passed in by the event notifier.
89 
90 **/
91 VOID
92 EFIAPI
93 IpIoTransmitHandlerDpc (
94   IN VOID      *Context
95   );
96 
97 
98 /**
99   Notify function for IP transmit token.
100 
101   @param[in]  Event                 The event signaled.
102   @param[in]  Context               The context passed in by the event notifier.
103 
104 **/
105 VOID
106 EFIAPI
107 IpIoTransmitHandler (
108   IN EFI_EVENT Event,
109   IN VOID      *Context
110   );
111 
112 
113 /**
114   This function create an IP child ,open the IP protocol, and return the opened
115   IP protocol as Interface.
116 
117   @param[in]    ControllerHandle   The controller handle.
118   @param[in]    ImageHandle        The image handle.
119   @param[in]    ChildHandle        Pointer to the buffer to save the IP child handle.
120   @param[in]    IpVersion          The version of the IP protocol to use, either
121                                    IPv4 or IPv6.
122   @param[out]   Interface          Pointer used to get the IP protocol interface.
123 
124   @retval       EFI_SUCCESS        The IP child is created and the IP protocol
125                                    interface is retrieved.
126   @retval       EFI_UNSUPPORTED    Unsupported IpVersion.
127   @retval       Others             The required operation failed.
128 
129 **/
130 EFI_STATUS
131 IpIoCreateIpChildOpenProtocol (
132   IN  EFI_HANDLE  ControllerHandle,
133   IN  EFI_HANDLE  ImageHandle,
134   IN  EFI_HANDLE  *ChildHandle,
135   IN  UINT8       IpVersion,
136   OUT VOID        **Interface
137   )
138 {
139   EFI_STATUS  Status;
140   EFI_GUID    *ServiceBindingGuid;
141   EFI_GUID    *IpProtocolGuid;
142 
143   if (IpVersion == IP_VERSION_4) {
144     ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
145     IpProtocolGuid     = &gEfiIp4ProtocolGuid;
146   } else if (IpVersion == IP_VERSION_6){
147     ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
148     IpProtocolGuid     = &gEfiIp6ProtocolGuid;
149   } else {
150     return EFI_UNSUPPORTED;
151   }
152 
153   //
154   // Create an IP child.
155   //
156   Status = NetLibCreateServiceChild (
157              ControllerHandle,
158              ImageHandle,
159              ServiceBindingGuid,
160              ChildHandle
161              );
162   if (EFI_ERROR (Status)) {
163     return Status;
164   }
165 
166   //
167   // Open the IP protocol installed on the *ChildHandle.
168   //
169   Status = gBS->OpenProtocol (
170                   *ChildHandle,
171                   IpProtocolGuid,
172                   Interface,
173                   ImageHandle,
174                   ControllerHandle,
175                   EFI_OPEN_PROTOCOL_BY_DRIVER
176                   );
177   if (EFI_ERROR (Status)) {
178     //
179     // On failure, destroy the IP child.
180     //
181     NetLibDestroyServiceChild (
182       ControllerHandle,
183       ImageHandle,
184       ServiceBindingGuid,
185       *ChildHandle
186       );
187   }
188 
189   return Status;
190 }
191 
192 
193 /**
194   This function close the previously opened IP protocol and destroy the IP child.
195 
196   @param[in]  ControllerHandle    The controller handle.
197   @param[in]  ImageHandle         The image handle.
198   @param[in]  ChildHandle         The child handle of the IP child.
199   @param[in]  IpVersion           The version of the IP protocol to use, either
200                                   IPv4 or IPv6.
201 
202   @retval     EFI_SUCCESS         The IP protocol is closed and the relevant IP child
203                                   is destroyed.
204   @retval     EFI_UNSUPPORTED     Unsupported IpVersion.
205   @retval     Others              The required operation failed.
206 
207 **/
208 EFI_STATUS
209 IpIoCloseProtocolDestroyIpChild (
210   IN EFI_HANDLE  ControllerHandle,
211   IN EFI_HANDLE  ImageHandle,
212   IN EFI_HANDLE  ChildHandle,
213   IN UINT8       IpVersion
214   )
215 {
216   EFI_STATUS  Status;
217   EFI_GUID    *ServiceBindingGuid;
218   EFI_GUID    *IpProtocolGuid;
219 
220   if (IpVersion == IP_VERSION_4) {
221     ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
222     IpProtocolGuid     = &gEfiIp4ProtocolGuid;
223   } else if (IpVersion == IP_VERSION_6) {
224     ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
225     IpProtocolGuid     = &gEfiIp6ProtocolGuid;
226   } else {
227     return EFI_UNSUPPORTED;
228   }
229 
230   //
231   // Close the previously opened IP protocol.
232   //
233   Status = gBS->CloseProtocol (
234                   ChildHandle,
235                   IpProtocolGuid,
236                   ImageHandle,
237                   ControllerHandle
238                   );
239   if (EFI_ERROR (Status)) {
240     return Status;
241   }
242 
243   //
244   // Destroy the IP child.
245   //
246   return NetLibDestroyServiceChild (
247            ControllerHandle,
248            ImageHandle,
249            ServiceBindingGuid,
250            ChildHandle
251            );
252 }
253 
254 /**
255   This function handles ICMPv4 packets. It is the worker function of
256   IpIoIcmpHandler.
257 
258   @param[in]       IpIo            Pointer to the IP_IO instance.
259   @param[in, out]  Pkt             Pointer to the ICMPv4 packet.
260   @param[in]       Session         Pointer to the net session of this ICMPv4 packet.
261 
262   @retval          EFI_SUCCESS     The ICMPv4 packet is handled successfully.
263   @retval          EFI_ABORTED     This type of ICMPv4 packet is not supported.
264 
265 **/
266 EFI_STATUS
267 IpIoIcmpv4Handler (
268   IN     IP_IO                *IpIo,
269   IN OUT NET_BUF              *Pkt,
270   IN     EFI_NET_SESSION_DATA *Session
271   )
272 {
273   IP4_ICMP_ERROR_HEAD  *IcmpHdr;
274   EFI_IP4_HEADER       *IpHdr;
275   UINT8                IcmpErr;
276   UINT8                *PayLoadHdr;
277   UINT8                Type;
278   UINT8                Code;
279   UINT32               TrimBytes;
280 
281   ASSERT (IpIo != NULL);
282   ASSERT (Pkt != NULL);
283   ASSERT (Session != NULL);
284   ASSERT (IpIo->IpVersion == IP_VERSION_4);
285 
286   //
287   // Check the ICMP packet length.
288   //
289   if (Pkt->TotalSize < sizeof (IP4_ICMP_ERROR_HEAD)) {
290     return EFI_ABORTED;
291   }
292 
293   IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);
294   IpHdr   = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);
295 
296   if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {
297 
298     return EFI_ABORTED;
299   }
300 
301   Type = IcmpHdr->Head.Type;
302   Code = IcmpHdr->Head.Code;
303 
304   //
305   // Analyze the ICMP Error in this ICMP pkt
306   //
307   switch (Type) {
308   case ICMP_TYPE_UNREACH:
309     switch (Code) {
310     case ICMP_CODE_UNREACH_NET:
311     case ICMP_CODE_UNREACH_HOST:
312     case ICMP_CODE_UNREACH_PROTOCOL:
313     case ICMP_CODE_UNREACH_PORT:
314     case ICMP_CODE_UNREACH_SRCFAIL:
315       IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code);
316 
317       break;
318 
319     case ICMP_CODE_UNREACH_NEEDFRAG:
320       IcmpErr = ICMP_ERR_MSGSIZE;
321 
322       break;
323 
324     case ICMP_CODE_UNREACH_NET_UNKNOWN:
325     case ICMP_CODE_UNREACH_NET_PROHIB:
326     case ICMP_CODE_UNREACH_TOSNET:
327       IcmpErr = ICMP_ERR_UNREACH_NET;
328 
329       break;
330 
331     case ICMP_CODE_UNREACH_HOST_UNKNOWN:
332     case ICMP_CODE_UNREACH_ISOLATED:
333     case ICMP_CODE_UNREACH_HOST_PROHIB:
334     case ICMP_CODE_UNREACH_TOSHOST:
335       IcmpErr = ICMP_ERR_UNREACH_HOST;
336 
337       break;
338 
339     default:
340       return EFI_ABORTED;
341     }
342 
343     break;
344 
345   case ICMP_TYPE_TIMXCEED:
346     if (Code > 1) {
347       return EFI_ABORTED;
348     }
349 
350     IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS);
351 
352     break;
353 
354   case ICMP_TYPE_PARAMPROB:
355     if (Code > 1) {
356       return EFI_ABORTED;
357     }
358 
359     IcmpErr = ICMP_ERR_PARAMPROB;
360 
361     break;
362 
363   case ICMP_TYPE_SOURCEQUENCH:
364     if (Code != 0) {
365       return EFI_ABORTED;
366     }
367 
368     IcmpErr = ICMP_ERR_QUENCH;
369 
370     break;
371 
372   default:
373     return EFI_ABORTED;
374   }
375 
376   //
377   // Notify user the ICMP pkt only containing payload except
378   // IP and ICMP header
379   //
380   PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));
381   TrimBytes  = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
382 
383   NetbufTrim (Pkt, TrimBytes, TRUE);
384 
385   //
386   // If the input packet has invalid format, and TrimBytes is larger than
387   // the packet size, the NetbufTrim might trim the packet to zero.
388   //
389   if (Pkt->TotalSize != 0) {
390     IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
391   }
392 
393   return EFI_SUCCESS;
394 }
395 
396 /**
397   This function handles ICMPv6 packets. It is the worker function of
398   IpIoIcmpHandler.
399 
400   @param[in]       IpIo            Pointer to the IP_IO instance.
401   @param[in, out]  Pkt             Pointer to the ICMPv6 packet.
402   @param[in]       Session         Pointer to the net session of this ICMPv6 packet.
403 
404   @retval          EFI_SUCCESS     The ICMPv6 packet is handled successfully.
405   @retval          EFI_ABORTED     This type of ICMPv6 packet is not supported.
406 
407 **/
408 EFI_STATUS
409 IpIoIcmpv6Handler (
410   IN     IP_IO                *IpIo,
411   IN OUT NET_BUF              *Pkt,
412   IN     EFI_NET_SESSION_DATA *Session
413   )
414 {
415   IP6_ICMP_ERROR_HEAD  *IcmpHdr;
416   EFI_IP6_HEADER       *IpHdr;
417   UINT8                IcmpErr;
418   UINT8                *PayLoadHdr;
419   UINT8                Type;
420   UINT8                Code;
421   UINT8                NextHeader;
422   UINT32               TrimBytes;
423   BOOLEAN              Flag;
424 
425   ASSERT (IpIo != NULL);
426   ASSERT (Pkt != NULL);
427   ASSERT (Session != NULL);
428   ASSERT (IpIo->IpVersion == IP_VERSION_6);
429 
430   //
431   // Check the ICMPv6 packet length.
432   //
433   if (Pkt->TotalSize < sizeof (IP6_ICMP_ERROR_HEAD)) {
434 
435     return EFI_ABORTED;
436   }
437 
438   IcmpHdr = NET_PROTO_HDR (Pkt, IP6_ICMP_ERROR_HEAD);
439   Type    = IcmpHdr->Head.Type;
440   Code    = IcmpHdr->Head.Code;
441 
442   //
443   // Analyze the ICMPv6 Error in this ICMPv6 packet
444   //
445   switch (Type) {
446   case ICMP_V6_DEST_UNREACHABLE:
447     switch (Code) {
448     case ICMP_V6_NO_ROUTE_TO_DEST:
449     case ICMP_V6_BEYOND_SCOPE:
450     case ICMP_V6_ROUTE_REJECTED:
451       IcmpErr = ICMP6_ERR_UNREACH_NET;
452 
453       break;
454 
455     case ICMP_V6_COMM_PROHIBITED:
456     case ICMP_V6_ADDR_UNREACHABLE:
457     case ICMP_V6_SOURCE_ADDR_FAILED:
458       IcmpErr = ICMP6_ERR_UNREACH_HOST;
459 
460       break;
461 
462     case ICMP_V6_PORT_UNREACHABLE:
463       IcmpErr = ICMP6_ERR_UNREACH_PORT;
464 
465       break;
466 
467      default:
468       return EFI_ABORTED;
469     }
470 
471     break;
472 
473   case ICMP_V6_PACKET_TOO_BIG:
474     if (Code >= 1) {
475       return EFI_ABORTED;
476     }
477 
478     IcmpErr = ICMP6_ERR_PACKAGE_TOOBIG;
479 
480     break;
481 
482   case ICMP_V6_TIME_EXCEEDED:
483     if (Code > 1) {
484       return EFI_ABORTED;
485     }
486 
487     IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code);
488 
489     break;
490 
491   case ICMP_V6_PARAMETER_PROBLEM:
492     if (Code > 3) {
493       return EFI_ABORTED;
494     }
495 
496     IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code);
497 
498     break;
499 
500    default:
501 
502      return EFI_ABORTED;
503    }
504 
505   //
506   // Notify user the ICMPv6 packet only containing payload except
507   // IPv6 basic header, extension header and ICMP header
508   //
509 
510   IpHdr      = (EFI_IP6_HEADER *) (&IcmpHdr->IpHead);
511   NextHeader = IpHdr->NextHeader;
512   PayLoadHdr = (UINT8 *) ((UINT8 *) IcmpHdr + sizeof (IP6_ICMP_ERROR_HEAD));
513   Flag       = TRUE;
514 
515   do {
516     switch (NextHeader) {
517     case EFI_IP_PROTO_UDP:
518     case EFI_IP_PROTO_TCP:
519     case EFI_IP_PROTO_ICMP:
520     case IP6_NO_NEXT_HEADER:
521       Flag = FALSE;
522 
523       break;
524 
525     case IP6_HOP_BY_HOP:
526     case IP6_DESTINATION:
527       //
528       // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
529       // the first 8 octets.
530       //
531       NextHeader = *(PayLoadHdr);
532       PayLoadHdr = (UINT8 *) (PayLoadHdr + (*(PayLoadHdr + 1) + 1) * 8);
533 
534       break;
535 
536     case IP6_FRAGMENT:
537       //
538       // The Fragment Header Length is 8 octets.
539       //
540       NextHeader = *(PayLoadHdr);
541       PayLoadHdr = (UINT8 *) (PayLoadHdr + 8);
542 
543       break;
544 
545     default:
546 
547       return EFI_ABORTED;
548     }
549   } while (Flag);
550 
551   TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
552 
553   NetbufTrim (Pkt, TrimBytes, TRUE);
554 
555   //
556   // If the input packet has invalid format, and TrimBytes is larger than
557   // the packet size, the NetbufTrim might trim the packet to zero.
558   //
559   if (Pkt->TotalSize != 0) {
560     IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
561   }
562 
563   return EFI_SUCCESS;
564 }
565 
566 /**
567   This function handles ICMP packets.
568 
569   @param[in]       IpIo            Pointer to the IP_IO instance.
570   @param[in, out]  Pkt             Pointer to the ICMP packet.
571   @param[in]       Session         Pointer to the net session of this ICMP packet.
572 
573   @retval          EFI_SUCCESS     The ICMP packet is handled successfully.
574   @retval          EFI_ABORTED     This type of ICMP packet is not supported.
575   @retval          EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
576 
577 **/
578 EFI_STATUS
579 IpIoIcmpHandler (
580   IN     IP_IO                *IpIo,
581   IN OUT NET_BUF              *Pkt,
582   IN     EFI_NET_SESSION_DATA *Session
583   )
584 {
585 
586   if (IpIo->IpVersion == IP_VERSION_4) {
587 
588     return IpIoIcmpv4Handler (IpIo, Pkt, Session);
589 
590   } else if (IpIo->IpVersion == IP_VERSION_6) {
591 
592     return IpIoIcmpv6Handler (IpIo, Pkt, Session);
593 
594   } else {
595 
596     return EFI_UNSUPPORTED;
597   }
598 }
599 
600 
601 /**
602   Free function for receive token of IP_IO. It is used to
603   signal the recycle event to notify IP to recycle the
604   data buffer.
605 
606   @param[in]  Event                 The event to be signaled.
607 
608 **/
609 VOID
610 EFIAPI
611 IpIoExtFree (
612   IN VOID  *Event
613   )
614 {
615   gBS->SignalEvent ((EFI_EVENT) Event);
616 }
617 
618 
619 /**
620   Create a send entry to wrap a packet before sending
621   out it through IP.
622 
623   @param[in, out]  IpIo                 Pointer to the IP_IO instance.
624   @param[in, out]  Pkt                  Pointer to the packet.
625   @param[in]       Sender               Pointer to the IP sender.
626   @param[in]       Context              Pointer to the context.
627   @param[in]       NotifyData           Pointer to the notify data.
628   @param[in]       Dest                 Pointer to the destination IP address.
629   @param[in]       Override             Pointer to the overridden IP_IO data.
630 
631   @return Pointer to the data structure created to wrap the packet. If any error occurs,
632           then return NULL.
633 
634 **/
635 IP_IO_SEND_ENTRY *
636 IpIoCreateSndEntry (
637   IN OUT IP_IO             *IpIo,
638   IN OUT NET_BUF           *Pkt,
639   IN     IP_IO_IP_PROTOCOL Sender,
640   IN     VOID              *Context    OPTIONAL,
641   IN     VOID              *NotifyData OPTIONAL,
642   IN     EFI_IP_ADDRESS    *Dest       OPTIONAL,
643   IN     IP_IO_OVERRIDE    *Override
644   )
645 {
646   IP_IO_SEND_ENTRY          *SndEntry;
647   EFI_EVENT                 Event;
648   EFI_STATUS                Status;
649   NET_FRAGMENT              *ExtFragment;
650   UINT32                    FragmentCount;
651   IP_IO_OVERRIDE            *OverrideData;
652   IP_IO_IP_TX_DATA          *TxData;
653   EFI_IP4_TRANSMIT_DATA     *Ip4TxData;
654   EFI_IP6_TRANSMIT_DATA     *Ip6TxData;
655 
656   if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {
657     return NULL;
658   }
659 
660   Event        = NULL;
661   TxData       = NULL;
662   OverrideData = NULL;
663 
664   //
665   // Allocate resource for SndEntry
666   //
667   SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
668   if (NULL == SndEntry) {
669     return NULL;
670   }
671 
672   Status = gBS->CreateEvent (
673                   EVT_NOTIFY_SIGNAL,
674                   TPL_NOTIFY,
675                   IpIoTransmitHandler,
676                   SndEntry,
677                   &Event
678                   );
679   if (EFI_ERROR (Status)) {
680     goto ON_ERROR;
681   }
682 
683   FragmentCount = Pkt->BlockOpNum;
684 
685   //
686   // Allocate resource for TxData
687   //
688   TxData = (IP_IO_IP_TX_DATA *) AllocatePool (
689     sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)
690     );
691 
692   if (NULL == TxData) {
693     goto ON_ERROR;
694   }
695 
696   //
697   // Build a fragment table to contain the fragments in the packet.
698   //
699   if (IpIo->IpVersion == IP_VERSION_4) {
700     ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;
701   } else {
702     ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;
703   }
704 
705   NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);
706 
707 
708   //
709   // Allocate resource for OverrideData if needed
710   //
711   if (NULL != Override) {
712 
713     OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);
714     if (NULL == OverrideData) {
715       goto ON_ERROR;
716     }
717   }
718 
719   //
720   // Set other fields of TxData except the fragment table
721   //
722   if (IpIo->IpVersion == IP_VERSION_4) {
723 
724     Ip4TxData = &TxData->Ip4TxData;
725 
726     IP4_COPY_ADDRESS (&Ip4TxData->DestinationAddress, Dest);
727 
728     Ip4TxData->OverrideData    = &OverrideData->Ip4OverrideData;
729     Ip4TxData->OptionsLength   = 0;
730     Ip4TxData->OptionsBuffer   = NULL;
731     Ip4TxData->TotalDataLength = Pkt->TotalSize;
732     Ip4TxData->FragmentCount   = FragmentCount;
733 
734     //
735     // Set the fields of SndToken
736     //
737     SndEntry->SndToken.Ip4Token.Event         = Event;
738     SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;
739   } else {
740 
741     Ip6TxData = &TxData->Ip6TxData;
742 
743     if (Dest != NULL) {
744       CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));
745     } else {
746       ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
747     }
748 
749     Ip6TxData->OverrideData  = &OverrideData->Ip6OverrideData;
750     Ip6TxData->DataLength    = Pkt->TotalSize;
751     Ip6TxData->FragmentCount = FragmentCount;
752     Ip6TxData->ExtHdrsLength = 0;
753     Ip6TxData->ExtHdrs       = NULL;
754 
755     //
756     // Set the fields of SndToken
757     //
758     SndEntry->SndToken.Ip6Token.Event         = Event;
759     SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;
760   }
761 
762   //
763   // Set the fields of SndEntry
764   //
765   SndEntry->IpIo        = IpIo;
766   SndEntry->Ip          = Sender;
767   SndEntry->Context     = Context;
768   SndEntry->NotifyData  = NotifyData;
769 
770   SndEntry->Pkt         = Pkt;
771   NET_GET_REF (Pkt);
772 
773   InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
774 
775   return SndEntry;
776 
777 ON_ERROR:
778 
779   if (OverrideData != NULL) {
780     FreePool (OverrideData);
781   }
782 
783   if (TxData != NULL) {
784     FreePool (TxData);
785   }
786 
787   if (SndEntry != NULL) {
788     FreePool (SndEntry);
789   }
790 
791   if (Event != NULL) {
792     gBS->CloseEvent (Event);
793   }
794 
795   return NULL;
796 }
797 
798 
799 /**
800   Destroy the SndEntry.
801 
802   This function pairs with IpIoCreateSndEntry().
803 
804   @param[in]  SndEntry              Pointer to the send entry to be destroyed.
805 
806 **/
807 VOID
808 IpIoDestroySndEntry (
809   IN IP_IO_SEND_ENTRY  *SndEntry
810   )
811 {
812   EFI_EVENT         Event;
813   IP_IO_IP_TX_DATA  *TxData;
814   IP_IO_OVERRIDE    *Override;
815 
816   if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {
817     Event              = SndEntry->SndToken.Ip4Token.Event;
818     TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;
819     Override           = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;
820   } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {
821     Event              = SndEntry->SndToken.Ip6Token.Event;
822     TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;
823     Override           = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;
824   } else {
825     return ;
826   }
827 
828   gBS->CloseEvent (Event);
829 
830   FreePool (TxData);
831 
832   if (NULL != Override) {
833     FreePool (Override);
834   }
835 
836   NetbufFree (SndEntry->Pkt);
837 
838   RemoveEntryList (&SndEntry->Entry);
839 
840   FreePool (SndEntry);
841 }
842 
843 
844 /**
845   Notify function for IP transmit token.
846 
847   @param[in]  Context               The context passed in by the event notifier.
848 
849 **/
850 VOID
851 EFIAPI
852 IpIoTransmitHandlerDpc (
853   IN VOID      *Context
854   )
855 {
856   IP_IO             *IpIo;
857   IP_IO_SEND_ENTRY  *SndEntry;
858   EFI_STATUS        Status;
859 
860   SndEntry  = (IP_IO_SEND_ENTRY *) Context;
861 
862   IpIo      = SndEntry->IpIo;
863 
864   if (IpIo->IpVersion == IP_VERSION_4) {
865     Status = SndEntry->SndToken.Ip4Token.Status;
866   } else if (IpIo->IpVersion == IP_VERSION_6){
867     Status = SndEntry->SndToken.Ip6Token.Status;
868   } else {
869     return ;
870   }
871 
872   if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {
873     IpIo->PktSentNotify (
874             Status,
875             SndEntry->Context,
876             SndEntry->Ip,
877             SndEntry->NotifyData
878             );
879   }
880 
881   IpIoDestroySndEntry (SndEntry);
882 }
883 
884 
885 /**
886   Notify function for IP transmit token.
887 
888   @param[in]  Event                 The event signaled.
889   @param[in]  Context               The context passed in by the event notifier.
890 
891 **/
892 VOID
893 EFIAPI
894 IpIoTransmitHandler (
895   IN EFI_EVENT Event,
896   IN VOID      *Context
897   )
898 {
899   //
900   // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
901   //
902   QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
903 }
904 
905 
906 /**
907   The dummy handler for the dummy IP receive token.
908 
909   @param[in]  Context               The context passed in by the event notifier.
910 
911 **/
912 VOID
913 EFIAPI
914 IpIoDummyHandlerDpc (
915   IN VOID      *Context
916   )
917 {
918   IP_IO_IP_INFO             *IpInfo;
919   EFI_STATUS                 Status;
920   EFI_EVENT                  RecycleEvent;
921 
922   IpInfo      = (IP_IO_IP_INFO *) Context;
923 
924   if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {
925     return ;
926   }
927 
928   RecycleEvent = NULL;
929 
930   if (IpInfo->IpVersion == IP_VERSION_4) {
931     Status = IpInfo->DummyRcvToken.Ip4Token.Status;
932 
933     if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {
934       RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;
935     }
936   } else {
937     Status = IpInfo->DummyRcvToken.Ip6Token.Status;
938 
939     if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {
940       RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;
941     }
942   }
943 
944 
945 
946   if (EFI_ABORTED == Status) {
947     //
948     // The reception is actively aborted by the consumer, directly return.
949     //
950     return;
951   } else if (EFI_SUCCESS == Status) {
952     //
953     // Recycle the RxData.
954     //
955     ASSERT (RecycleEvent != NULL);
956 
957     gBS->SignalEvent (RecycleEvent);
958   }
959 
960   //
961   // Continue the receive.
962   //
963   if (IpInfo->IpVersion == IP_VERSION_4) {
964     IpInfo->Ip.Ip4->Receive (
965                       IpInfo->Ip.Ip4,
966                       &IpInfo->DummyRcvToken.Ip4Token
967                       );
968   } else {
969     IpInfo->Ip.Ip6->Receive (
970                       IpInfo->Ip.Ip6,
971                       &IpInfo->DummyRcvToken.Ip6Token
972                       );
973   }
974 }
975 
976 
977 /**
978   This function add IpIoDummyHandlerDpc to the end of the DPC queue.
979 
980   @param[in]  Event                 The event signaled.
981   @param[in]  Context               The context passed in by the event notifier.
982 
983 **/
984 VOID
985 EFIAPI
986 IpIoDummyHandler (
987   IN EFI_EVENT Event,
988   IN VOID      *Context
989   )
990 {
991   //
992   // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
993   //
994   QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
995 }
996 
997 
998 /**
999   Notify function for the IP receive token, used to process
1000   the received IP packets.
1001 
1002   @param[in]  Context               The context passed in by the event notifier.
1003 
1004 **/
1005 VOID
1006 EFIAPI
1007 IpIoListenHandlerDpc (
1008   IN VOID      *Context
1009   )
1010 {
1011   IP_IO                 *IpIo;
1012   EFI_STATUS            Status;
1013   IP_IO_IP_RX_DATA      *RxData;
1014   EFI_NET_SESSION_DATA  Session;
1015   NET_BUF               *Pkt;
1016 
1017   IpIo = (IP_IO *) Context;
1018 
1019   if (IpIo->IpVersion == IP_VERSION_4) {
1020     Status = IpIo->RcvToken.Ip4Token.Status;
1021     RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;
1022   } else if (IpIo->IpVersion == IP_VERSION_6) {
1023     Status = IpIo->RcvToken.Ip6Token.Status;
1024     RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;
1025   } else {
1026     return;
1027   }
1028 
1029   if (EFI_ABORTED == Status) {
1030     //
1031     // The reception is actively aborted by the consumer, directly return.
1032     //
1033     return;
1034   }
1035 
1036   if ((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) {
1037     //
1038     // Only process the normal packets and the icmp error packets.
1039     //
1040     if (RxData != NULL) {
1041       goto CleanUp;
1042     } else {
1043       goto Resume;
1044     }
1045   }
1046 
1047   //
1048   // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).
1049   //
1050   ASSERT (RxData != NULL);
1051   if (RxData == NULL) {
1052     goto Resume;
1053   }
1054 
1055   if (NULL == IpIo->PktRcvdNotify) {
1056     goto CleanUp;
1057   }
1058 
1059   if (IpIo->IpVersion == IP_VERSION_4) {
1060     ASSERT (RxData->Ip4RxData.Header != NULL);
1061     if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress))) {
1062       //
1063       // The source address is a broadcast address, discard it.
1064       //
1065       goto CleanUp;
1066     }
1067     if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&
1068         (IpIo->SubnetMask != 0) &&
1069         IP4_NET_EQUAL (IpIo->StationIp, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask) &&
1070         !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask)) {
1071       //
1072       // The source address doesn't match StationIp and it's not a unicast IP address, discard it.
1073       //
1074       goto CleanUp;
1075     }
1076 
1077     if (RxData->Ip4RxData.DataLength == 0) {
1078       //
1079       // Discard zero length data payload packet.
1080       //
1081       goto CleanUp;
1082     }
1083 
1084     //
1085     // The fragment should always be valid for non-zero length packet.
1086     //
1087     ASSERT (RxData->Ip4RxData.FragmentCount != 0);
1088 
1089     //
1090     // Create a netbuffer representing IPv4 packet
1091     //
1092     Pkt = NetbufFromExt (
1093             (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,
1094             RxData->Ip4RxData.FragmentCount,
1095             0,
1096             0,
1097             IpIoExtFree,
1098             RxData->Ip4RxData.RecycleSignal
1099             );
1100     if (NULL == Pkt) {
1101       goto CleanUp;
1102     }
1103 
1104     //
1105     // Create a net session
1106     //
1107     Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);
1108     Session.Dest.Addr[0]   = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);
1109     Session.IpHdr.Ip4Hdr   = RxData->Ip4RxData.Header;
1110     Session.IpHdrLen       = RxData->Ip4RxData.HeaderLength;
1111     Session.IpVersion      = IP_VERSION_4;
1112   } else {
1113     ASSERT (RxData->Ip6RxData.Header != NULL);
1114     if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {
1115       goto CleanUp;
1116     }
1117 
1118     if (RxData->Ip6RxData.DataLength == 0) {
1119       //
1120       // Discard zero length data payload packet.
1121       //
1122       goto CleanUp;
1123     }
1124 
1125     //
1126     // The fragment should always be valid for non-zero length packet.
1127     //
1128     ASSERT (RxData->Ip6RxData.FragmentCount != 0);
1129 
1130     //
1131     // Create a netbuffer representing IPv6 packet
1132     //
1133     Pkt = NetbufFromExt (
1134             (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,
1135             RxData->Ip6RxData.FragmentCount,
1136             0,
1137             0,
1138             IpIoExtFree,
1139             RxData->Ip6RxData.RecycleSignal
1140             );
1141     if (NULL == Pkt) {
1142       goto CleanUp;
1143     }
1144 
1145     //
1146     // Create a net session
1147     //
1148     CopyMem (
1149       &Session.Source,
1150       &RxData->Ip6RxData.Header->SourceAddress,
1151       sizeof(EFI_IPv6_ADDRESS)
1152       );
1153     CopyMem (
1154       &Session.Dest,
1155       &RxData->Ip6RxData.Header->DestinationAddress,
1156       sizeof(EFI_IPv6_ADDRESS)
1157       );
1158     Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;
1159     Session.IpHdrLen     = RxData->Ip6RxData.HeaderLength;
1160     Session.IpVersion    = IP_VERSION_6;
1161   }
1162 
1163   if (EFI_SUCCESS == Status) {
1164 
1165     IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);
1166   } else {
1167     //
1168     // Status is EFI_ICMP_ERROR
1169     //
1170     Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
1171     if (EFI_ERROR (Status)) {
1172       NetbufFree (Pkt);
1173     }
1174   }
1175 
1176   goto Resume;
1177 
1178 CleanUp:
1179 
1180   if (IpIo->IpVersion == IP_VERSION_4){
1181     gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);
1182   } else {
1183     gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);
1184   }
1185 
1186 Resume:
1187 
1188   if (IpIo->IpVersion == IP_VERSION_4){
1189     IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));
1190   } else {
1191     IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));
1192   }
1193 }
1194 
1195 /**
1196   This function add IpIoListenHandlerDpc to the end of the DPC queue.
1197 
1198   @param[in]  Event                The event signaled.
1199   @param[in]  Context              The context passed in by the event notifier.
1200 
1201 **/
1202 VOID
1203 EFIAPI
1204 IpIoListenHandler (
1205   IN EFI_EVENT Event,
1206   IN VOID      *Context
1207   )
1208 {
1209   //
1210   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1211   //
1212   QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
1213 }
1214 
1215 
1216 /**
1217   Create a new IP_IO instance.
1218 
1219   If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1220 
1221   This function uses IP4/IP6 service binding protocol in Controller to create
1222   an IP4/IP6 child (aka IP4/IP6 instance).
1223 
1224   @param[in]  Image             The image handle of the driver or application that
1225                                 consumes IP_IO.
1226   @param[in]  Controller        The controller handle that has IP4 or IP6 service
1227                                 binding protocol installed.
1228   @param[in]  IpVersion         The version of the IP protocol to use, either
1229                                 IPv4 or IPv6.
1230 
1231   @return Pointer to a newly created IP_IO instance, or NULL if failed.
1232 
1233 **/
1234 IP_IO *
1235 EFIAPI
1236 IpIoCreate (
1237   IN EFI_HANDLE Image,
1238   IN EFI_HANDLE Controller,
1239   IN UINT8      IpVersion
1240   )
1241 {
1242   EFI_STATUS  Status;
1243   IP_IO       *IpIo;
1244   EFI_EVENT   Event;
1245 
1246   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1247 
1248   IpIo = AllocateZeroPool (sizeof (IP_IO));
1249   if (NULL == IpIo) {
1250     return NULL;
1251   }
1252 
1253   InitializeListHead (&(IpIo->PendingSndList));
1254   InitializeListHead (&(IpIo->IpList));
1255   IpIo->Controller  = Controller;
1256   IpIo->Image       = Image;
1257   IpIo->IpVersion   = IpVersion;
1258   Event             = NULL;
1259 
1260   Status = gBS->CreateEvent (
1261                   EVT_NOTIFY_SIGNAL,
1262                   TPL_NOTIFY,
1263                   IpIoListenHandler,
1264                   IpIo,
1265                   &Event
1266                   );
1267   if (EFI_ERROR (Status)) {
1268     goto ReleaseIpIo;
1269   }
1270 
1271   if (IpVersion == IP_VERSION_4) {
1272     IpIo->RcvToken.Ip4Token.Event = Event;
1273   } else {
1274     IpIo->RcvToken.Ip6Token.Event = Event;
1275   }
1276 
1277   //
1278   // Create an IP child and open IP protocol
1279   //
1280   Status = IpIoCreateIpChildOpenProtocol (
1281              Controller,
1282              Image,
1283              &IpIo->ChildHandle,
1284              IpVersion,
1285              (VOID **) & (IpIo->Ip)
1286              );
1287   if (EFI_ERROR (Status)) {
1288     goto ReleaseIpIo;
1289   }
1290 
1291   return IpIo;
1292 
1293 ReleaseIpIo:
1294 
1295   if (Event != NULL) {
1296     gBS->CloseEvent (Event);
1297   }
1298 
1299   gBS->FreePool (IpIo);
1300 
1301   return NULL;
1302 }
1303 
1304 
1305 /**
1306   Open an IP_IO instance for use.
1307 
1308   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1309 
1310   This function is called after IpIoCreate(). It is used for configuring the IP
1311   instance and register the callbacks and their context data for sending and
1312   receiving IP packets.
1313 
1314   @param[in, out]  IpIo               Pointer to an IP_IO instance that needs
1315                                       to open.
1316   @param[in]       OpenData           The configuration data and callbacks for
1317                                       the IP_IO instance.
1318 
1319   @retval          EFI_SUCCESS            The IP_IO instance opened with OpenData
1320                                           successfully.
1321   @retval          EFI_ACCESS_DENIED      The IP_IO instance is configured, avoid to
1322                                           reopen it.
1323   @retval          EFI_UNSUPPORTED        IPv4 RawData mode is no supported.
1324   @retval          EFI_INVALID_PARAMETER  Invalid input parameter.
1325   @retval          Others                 Error condition occurred.
1326 
1327 **/
1328 EFI_STATUS
1329 EFIAPI
1330 IpIoOpen (
1331   IN OUT IP_IO           *IpIo,
1332   IN     IP_IO_OPEN_DATA *OpenData
1333   )
1334 {
1335   EFI_STATUS        Status;
1336   UINT8             IpVersion;
1337 
1338   if (IpIo == NULL || OpenData == NULL) {
1339     return EFI_INVALID_PARAMETER;
1340   }
1341 
1342   if (IpIo->IsConfigured) {
1343     return EFI_ACCESS_DENIED;
1344   }
1345 
1346   IpVersion = IpIo->IpVersion;
1347 
1348   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1349 
1350   //
1351   // configure ip
1352   //
1353   if (IpVersion == IP_VERSION_4){
1354     //
1355     // RawData mode is no supported.
1356     //
1357     ASSERT (!OpenData->IpConfigData.Ip4CfgData.RawData);
1358     if (OpenData->IpConfigData.Ip4CfgData.RawData) {
1359       return EFI_UNSUPPORTED;
1360     }
1361 
1362     if (!OpenData->IpConfigData.Ip4CfgData.UseDefaultAddress) {
1363       IpIo->StationIp = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.StationAddress);
1364       IpIo->SubnetMask = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.SubnetMask);
1365     }
1366 
1367     Status = IpIo->Ip.Ip4->Configure (
1368                              IpIo->Ip.Ip4,
1369                              &OpenData->IpConfigData.Ip4CfgData
1370                              );
1371   } else {
1372 
1373     Status = IpIo->Ip.Ip6->Configure (
1374                              IpIo->Ip.Ip6,
1375                              &OpenData->IpConfigData.Ip6CfgData
1376                              );
1377   }
1378 
1379   if (EFI_ERROR (Status)) {
1380     return Status;
1381   }
1382 
1383   //
1384   // @bug To delete the default route entry in this Ip, if it is:
1385   // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1386   // @bug its code
1387   //
1388   if (IpVersion == IP_VERSION_4){
1389     Status = IpIo->Ip.Ip4->Routes (
1390                              IpIo->Ip.Ip4,
1391                              TRUE,
1392                              &mZeroIp4Addr,
1393                              &mZeroIp4Addr,
1394                              &mZeroIp4Addr
1395                              );
1396 
1397     if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
1398       return Status;
1399     }
1400   }
1401 
1402   IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
1403   IpIo->PktSentNotify = OpenData->PktSentNotify;
1404 
1405   IpIo->RcvdContext   = OpenData->RcvdContext;
1406   IpIo->SndContext    = OpenData->SndContext;
1407 
1408   if (IpVersion == IP_VERSION_4){
1409     IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;
1410 
1411     //
1412     // start to listen incoming packet
1413     //
1414     Status = IpIo->Ip.Ip4->Receive (
1415                              IpIo->Ip.Ip4,
1416                              &(IpIo->RcvToken.Ip4Token)
1417                              );
1418     if (EFI_ERROR (Status)) {
1419       IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
1420       return Status;
1421     }
1422 
1423   } else {
1424 
1425     IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;
1426     Status = IpIo->Ip.Ip6->Receive (
1427                              IpIo->Ip.Ip6,
1428                              &(IpIo->RcvToken.Ip6Token)
1429                              );
1430     if (EFI_ERROR (Status)) {
1431       IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
1432       return Status;
1433     }
1434   }
1435 
1436   IpIo->IsConfigured = TRUE;
1437   InsertTailList (&mActiveIpIoList, &IpIo->Entry);
1438 
1439   return Status;
1440 }
1441 
1442 
1443 /**
1444   Stop an IP_IO instance.
1445 
1446   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1447 
1448   This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1449   the pending send/receive tokens will be canceled.
1450 
1451   @param[in, out]  IpIo            Pointer to the IP_IO instance that needs to stop.
1452 
1453   @retval          EFI_SUCCESS            The IP_IO instance stopped successfully.
1454   @retval          EFI_INVALID_PARAMETER  Invalid input parameter.
1455   @retval          Others                 Error condition occurred.
1456 
1457 **/
1458 EFI_STATUS
1459 EFIAPI
1460 IpIoStop (
1461   IN OUT IP_IO *IpIo
1462   )
1463 {
1464   EFI_STATUS        Status;
1465   IP_IO_IP_INFO     *IpInfo;
1466   UINT8             IpVersion;
1467 
1468   if (IpIo == NULL) {
1469     return EFI_INVALID_PARAMETER;
1470   }
1471 
1472   if (!IpIo->IsConfigured) {
1473     return EFI_SUCCESS;
1474   }
1475 
1476   IpVersion = IpIo->IpVersion;
1477 
1478   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1479 
1480   //
1481   // Remove the IpIo from the active IpIo list.
1482   //
1483   RemoveEntryList (&IpIo->Entry);
1484 
1485   //
1486   // Configure NULL Ip
1487   //
1488   if (IpVersion == IP_VERSION_4) {
1489     Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
1490   } else {
1491     Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
1492   }
1493   if (EFI_ERROR (Status)) {
1494     return Status;
1495   }
1496 
1497   IpIo->IsConfigured = FALSE;
1498 
1499   //
1500   // Destroy the Ip List used by IpIo
1501   //
1502 
1503   while (!IsListEmpty (&(IpIo->IpList))) {
1504     IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
1505 
1506     IpIoRemoveIp (IpIo, IpInfo);
1507   }
1508 
1509   //
1510   // All pending send tokens should be flushed by resetting the IP instances.
1511   //
1512   ASSERT (IsListEmpty (&IpIo->PendingSndList));
1513 
1514   //
1515   // Close the receive event.
1516   //
1517   if (IpVersion == IP_VERSION_4){
1518     gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);
1519   } else {
1520     gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);
1521   }
1522 
1523   return EFI_SUCCESS;
1524 }
1525 
1526 
1527 /**
1528   Destroy an IP_IO instance.
1529 
1530   This function is paired with IpIoCreate(). The IP_IO will be closed first.
1531   Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1532 
1533   @param[in, out]  IpIo         Pointer to the IP_IO instance that needs to be
1534                                 destroyed.
1535 
1536   @retval          EFI_SUCCESS  The IP_IO instance destroyed successfully.
1537   @retval          Others       Error condition occurred.
1538 
1539 **/
1540 EFI_STATUS
1541 EFIAPI
1542 IpIoDestroy (
1543   IN OUT IP_IO *IpIo
1544   )
1545 {
1546   EFI_STATUS    Status;
1547 
1548   //
1549   // Stop the IpIo.
1550   //
1551   Status = IpIoStop (IpIo);
1552   if (EFI_ERROR (Status)) {
1553     return Status;
1554   }
1555 
1556   //
1557   // Close the IP protocol and destroy the child.
1558   //
1559   Status = IpIoCloseProtocolDestroyIpChild (
1560              IpIo->Controller,
1561              IpIo->Image,
1562              IpIo->ChildHandle,
1563              IpIo->IpVersion
1564              );
1565   if (EFI_ERROR (Status)) {
1566     return Status;
1567   }
1568 
1569   gBS->FreePool (IpIo);
1570 
1571   return EFI_SUCCESS;
1572 }
1573 
1574 
1575 /**
1576   Send out an IP packet.
1577 
1578   This function is called after IpIoOpen(). The data to be sent is wrapped in
1579   Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1580   overridden by Sender. Other sending configs, like source address and gateway
1581   address etc., are specified in OverrideData.
1582 
1583   @param[in, out]  IpIo                  Pointer to an IP_IO instance used for sending IP
1584                                          packet.
1585   @param[in, out]  Pkt                   Pointer to the IP packet to be sent.
1586   @param[in]       Sender                The IP protocol instance used for sending.
1587   @param[in]       Context               Optional context data.
1588   @param[in]       NotifyData            Optional notify data.
1589   @param[in]       Dest                  The destination IP address to send this packet to.
1590                                          This parameter is optional when using IPv6.
1591   @param[in]       OverrideData          The data to override some configuration of the IP
1592                                          instance used for sending.
1593 
1594   @retval          EFI_SUCCESS           The operation is completed successfully.
1595   @retval          EFI_INVALID_PARAMETER The input parameter is not correct.
1596   @retval          EFI_NOT_STARTED       The IpIo is not configured.
1597   @retval          EFI_OUT_OF_RESOURCES  Failed due to resource limit.
1598   @retval          Others                Error condition occurred.
1599 
1600 **/
1601 EFI_STATUS
1602 EFIAPI
1603 IpIoSend (
1604   IN OUT IP_IO          *IpIo,
1605   IN OUT NET_BUF        *Pkt,
1606   IN     IP_IO_IP_INFO  *Sender        OPTIONAL,
1607   IN     VOID           *Context       OPTIONAL,
1608   IN     VOID           *NotifyData    OPTIONAL,
1609   IN     EFI_IP_ADDRESS *Dest          OPTIONAL,
1610   IN     IP_IO_OVERRIDE *OverrideData  OPTIONAL
1611   )
1612 {
1613   EFI_STATUS        Status;
1614   IP_IO_IP_PROTOCOL Ip;
1615   IP_IO_SEND_ENTRY  *SndEntry;
1616 
1617   if ((IpIo == NULL) || (Pkt == NULL)) {
1618     return EFI_INVALID_PARAMETER;
1619   }
1620 
1621   if ((IpIo->IpVersion == IP_VERSION_4) && (Dest == NULL)) {
1622     return EFI_INVALID_PARAMETER;
1623   }
1624 
1625   if (!IpIo->IsConfigured) {
1626     return EFI_NOT_STARTED;
1627   }
1628 
1629   Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
1630 
1631   //
1632   // create a new SndEntry
1633   //
1634   SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
1635   if (NULL == SndEntry) {
1636     return EFI_OUT_OF_RESOURCES;
1637   }
1638 
1639   //
1640   // Send this Packet
1641   //
1642   if (IpIo->IpVersion == IP_VERSION_4){
1643     Status = Ip.Ip4->Transmit (
1644                        Ip.Ip4,
1645                        &SndEntry->SndToken.Ip4Token
1646                        );
1647   } else {
1648     Status = Ip.Ip6->Transmit (
1649                        Ip.Ip6,
1650                        &SndEntry->SndToken.Ip6Token
1651                        );
1652   }
1653 
1654   if (EFI_ERROR (Status)) {
1655     IpIoDestroySndEntry (SndEntry);
1656   }
1657 
1658   return Status;
1659 }
1660 
1661 
1662 /**
1663   Cancel the IP transmit token which wraps this Packet.
1664 
1665   If IpIo is NULL, then ASSERT().
1666   If Packet is NULL, then ASSERT().
1667 
1668   @param[in]  IpIo                  Pointer to the IP_IO instance.
1669   @param[in]  Packet                Pointer to the packet of NET_BUF to cancel.
1670 
1671 **/
1672 VOID
1673 EFIAPI
1674 IpIoCancelTxToken (
1675   IN IP_IO  *IpIo,
1676   IN VOID   *Packet
1677   )
1678 {
1679   LIST_ENTRY        *Node;
1680   IP_IO_SEND_ENTRY  *SndEntry;
1681   IP_IO_IP_PROTOCOL Ip;
1682 
1683   ASSERT ((IpIo != NULL) && (Packet != NULL));
1684 
1685   NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
1686 
1687     SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
1688 
1689     if (SndEntry->Pkt == Packet) {
1690 
1691       Ip = SndEntry->Ip;
1692 
1693       if (IpIo->IpVersion == IP_VERSION_4) {
1694         Ip.Ip4->Cancel (
1695                   Ip.Ip4,
1696                   &SndEntry->SndToken.Ip4Token
1697                   );
1698       } else {
1699         Ip.Ip6->Cancel (
1700                   Ip.Ip6,
1701                   &SndEntry->SndToken.Ip6Token
1702                   );
1703       }
1704 
1705       break;
1706     }
1707   }
1708 
1709 }
1710 
1711 
1712 /**
1713   Add a new IP instance for sending data.
1714 
1715   If IpIo is NULL, then ASSERT().
1716   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1717 
1718   The function is used to add the IP_IO to the IP_IO sending list. The caller
1719   can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1720   data.
1721 
1722   @param[in, out]  IpIo               Pointer to a IP_IO instance to add a new IP
1723                                       instance for sending purpose.
1724 
1725   @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1726 
1727 **/
1728 IP_IO_IP_INFO *
1729 EFIAPI
1730 IpIoAddIp (
1731   IN OUT IP_IO  *IpIo
1732   )
1733 {
1734   EFI_STATUS     Status;
1735   IP_IO_IP_INFO  *IpInfo;
1736   EFI_EVENT      Event;
1737 
1738   ASSERT (IpIo != NULL);
1739   ASSERT ((IpIo->IpVersion == IP_VERSION_4) || (IpIo->IpVersion == IP_VERSION_6));
1740 
1741   IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
1742   if (IpInfo == NULL) {
1743     return NULL;
1744   }
1745 
1746   //
1747   // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1748   // instance.
1749   //
1750   InitializeListHead (&IpInfo->Entry);
1751   IpInfo->ChildHandle = NULL;
1752   ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1753   ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1754 
1755   IpInfo->RefCnt    = 1;
1756   IpInfo->IpVersion = IpIo->IpVersion;
1757 
1758   //
1759   // Create the IP instance and open the IP protocol.
1760   //
1761   Status = IpIoCreateIpChildOpenProtocol (
1762              IpIo->Controller,
1763              IpIo->Image,
1764              &IpInfo->ChildHandle,
1765              IpInfo->IpVersion,
1766              (VOID **) &IpInfo->Ip
1767              );
1768   if (EFI_ERROR (Status)) {
1769     goto ReleaseIpInfo;
1770   }
1771 
1772   //
1773   // Create the event for the DummyRcvToken.
1774   //
1775   Status = gBS->CreateEvent (
1776                   EVT_NOTIFY_SIGNAL,
1777                   TPL_NOTIFY,
1778                   IpIoDummyHandler,
1779                   IpInfo,
1780                   &Event
1781                   );
1782   if (EFI_ERROR (Status)) {
1783     goto ReleaseIpChild;
1784   }
1785 
1786   if (IpInfo->IpVersion == IP_VERSION_4) {
1787     IpInfo->DummyRcvToken.Ip4Token.Event = Event;
1788   } else {
1789     IpInfo->DummyRcvToken.Ip6Token.Event = Event;
1790   }
1791 
1792   //
1793   // Link this IpInfo into the IpIo.
1794   //
1795   InsertTailList (&IpIo->IpList, &IpInfo->Entry);
1796 
1797   return IpInfo;
1798 
1799 ReleaseIpChild:
1800 
1801   IpIoCloseProtocolDestroyIpChild (
1802     IpIo->Controller,
1803     IpIo->Image,
1804     IpInfo->ChildHandle,
1805     IpInfo->IpVersion
1806     );
1807 
1808 ReleaseIpInfo:
1809 
1810   gBS->FreePool (IpInfo);
1811 
1812   return NULL;
1813 }
1814 
1815 
1816 /**
1817   Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1818   is not NULL.
1819 
1820   If IpInfo is NULL, then ASSERT().
1821   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1822 
1823   @param[in, out]  IpInfo          Pointer to the IP_IO_IP_INFO instance.
1824   @param[in, out]  IpConfigData    The IP configure data used to configure the IP
1825                                    instance, if NULL the IP instance is reset. If
1826                                    UseDefaultAddress is set to TRUE, and the configure
1827                                    operation succeeds, the default address information
1828                                    is written back in this IpConfigData.
1829 
1830   @retval          EFI_SUCCESS     The IP instance of this IpInfo is configured successfully
1831                                    or no need to reconfigure it.
1832   @retval          Others          Configuration fails.
1833 
1834 **/
1835 EFI_STATUS
1836 EFIAPI
1837 IpIoConfigIp (
1838   IN OUT IP_IO_IP_INFO        *IpInfo,
1839   IN OUT VOID                 *IpConfigData OPTIONAL
1840   )
1841 {
1842   EFI_STATUS         Status;
1843   IP_IO_IP_PROTOCOL  Ip;
1844   UINT8              IpVersion;
1845   EFI_IP4_MODE_DATA  Ip4ModeData;
1846   EFI_IP6_MODE_DATA  Ip6ModeData;
1847 
1848   ASSERT (IpInfo != NULL);
1849 
1850   if (IpInfo->RefCnt > 1) {
1851     //
1852     // This IP instance is shared, don't reconfigure it until it has only one
1853     // consumer. Currently, only the tcp children cloned from their passive parent
1854     // will share the same IP. So this cases only happens while IpConfigData is NULL,
1855     // let the last consumer clean the IP instance.
1856     //
1857     return EFI_SUCCESS;
1858   }
1859 
1860   IpVersion = IpInfo->IpVersion;
1861   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1862 
1863   Ip = IpInfo->Ip;
1864 
1865   if (IpInfo->IpVersion == IP_VERSION_4) {
1866     Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);
1867   } else {
1868     Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);
1869   }
1870 
1871   if (EFI_ERROR (Status)) {
1872     return Status;
1873   }
1874 
1875   if (IpConfigData != NULL) {
1876     if (IpInfo->IpVersion == IP_VERSION_4) {
1877 
1878       if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {
1879         Status = Ip.Ip4->GetModeData (
1880                            Ip.Ip4,
1881                            &Ip4ModeData,
1882                            NULL,
1883                            NULL
1884                            );
1885         if (EFI_ERROR (Status)) {
1886           Ip.Ip4->Configure (Ip.Ip4, NULL);
1887           return Status;
1888         }
1889 
1890         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);
1891         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);
1892       }
1893 
1894       CopyMem (
1895         &IpInfo->Addr.Addr,
1896         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,
1897         sizeof (IP4_ADDR)
1898         );
1899       CopyMem (
1900         &IpInfo->PreMask.SubnetMask,
1901         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,
1902         sizeof (IP4_ADDR)
1903         );
1904 
1905       Status = Ip.Ip4->Receive (
1906                          Ip.Ip4,
1907                          &IpInfo->DummyRcvToken.Ip4Token
1908                          );
1909       if (EFI_ERROR (Status)) {
1910         Ip.Ip4->Configure (Ip.Ip4, NULL);
1911       }
1912     } else {
1913       Status = Ip.Ip6->GetModeData (
1914                          Ip.Ip6,
1915                          &Ip6ModeData,
1916                          NULL,
1917                          NULL
1918                          );
1919       if (EFI_ERROR (Status)) {
1920         Ip.Ip6->Configure (Ip.Ip6, NULL);
1921         return Status;
1922       }
1923 
1924       if (Ip6ModeData.IsConfigured) {
1925         CopyMem (
1926           &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,
1927           &Ip6ModeData.ConfigData.StationAddress,
1928           sizeof (EFI_IPv6_ADDRESS)
1929           );
1930 
1931         if (Ip6ModeData.AddressList != NULL) {
1932           FreePool (Ip6ModeData.AddressList);
1933         }
1934 
1935         if (Ip6ModeData.GroupTable != NULL) {
1936           FreePool (Ip6ModeData.GroupTable);
1937         }
1938 
1939         if (Ip6ModeData.RouteTable != NULL) {
1940           FreePool (Ip6ModeData.RouteTable);
1941         }
1942 
1943         if (Ip6ModeData.NeighborCache != NULL) {
1944           FreePool (Ip6ModeData.NeighborCache);
1945         }
1946 
1947         if (Ip6ModeData.PrefixTable != NULL) {
1948           FreePool (Ip6ModeData.PrefixTable);
1949         }
1950 
1951         if (Ip6ModeData.IcmpTypeList != NULL) {
1952           FreePool (Ip6ModeData.IcmpTypeList);
1953         }
1954 
1955       } else {
1956         Status = EFI_NO_MAPPING;
1957         return Status;
1958       }
1959 
1960       CopyMem (
1961         &IpInfo->Addr,
1962         &Ip6ModeData.ConfigData.StationAddress,
1963         sizeof (EFI_IPv6_ADDRESS)
1964         );
1965 
1966       Status = Ip.Ip6->Receive (
1967                          Ip.Ip6,
1968                          &IpInfo->DummyRcvToken.Ip6Token
1969                          );
1970       if (EFI_ERROR (Status)) {
1971         Ip.Ip6->Configure (Ip.Ip6, NULL);
1972       }
1973     }
1974   } else {
1975     //
1976     // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1977     //
1978     ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1979     ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1980   }
1981 
1982   return Status;
1983 }
1984 
1985 
1986 /**
1987   Destroy an IP instance maintained in IpIo->IpList for
1988   sending purpose.
1989 
1990   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1991 
1992   This function pairs with IpIoAddIp(). The IpInfo is previously created by
1993   IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1994   will be destroyed if the RefCnt is zero.
1995 
1996   @param[in]  IpIo                  Pointer to the IP_IO instance.
1997   @param[in]  IpInfo                Pointer to the IpInfo to be removed.
1998 
1999 **/
2000 VOID
2001 EFIAPI
2002 IpIoRemoveIp (
2003   IN IP_IO            *IpIo,
2004   IN IP_IO_IP_INFO    *IpInfo
2005   )
2006 {
2007 
2008   UINT8               IpVersion;
2009 
2010   if (IpIo == NULL || IpInfo == NULL) {
2011     return;
2012   }
2013 
2014   ASSERT (IpInfo->RefCnt > 0);
2015 
2016   NET_PUT_REF (IpInfo);
2017 
2018   if (IpInfo->RefCnt > 0) {
2019 
2020     return;
2021   }
2022 
2023   IpVersion = IpIo->IpVersion;
2024 
2025   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
2026 
2027   RemoveEntryList (&IpInfo->Entry);
2028 
2029   if (IpVersion == IP_VERSION_4){
2030     IpInfo->Ip.Ip4->Configure (
2031                       IpInfo->Ip.Ip4,
2032                       NULL
2033                       );
2034     IpIoCloseProtocolDestroyIpChild (
2035       IpIo->Controller,
2036       IpIo->Image,
2037       IpInfo->ChildHandle,
2038       IP_VERSION_4
2039       );
2040 
2041     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);
2042 
2043   } else {
2044 
2045     IpInfo->Ip.Ip6->Configure (
2046                       IpInfo->Ip.Ip6,
2047                       NULL
2048                       );
2049 
2050     IpIoCloseProtocolDestroyIpChild (
2051       IpIo->Controller,
2052       IpIo->Image,
2053       IpInfo->ChildHandle,
2054       IP_VERSION_6
2055       );
2056 
2057     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);
2058   }
2059 
2060   FreePool (IpInfo);
2061 }
2062 
2063 
2064 /**
2065   Find the first IP protocol maintained in IpIo whose local
2066   address is the same as Src.
2067 
2068   This function is called when the caller needs the IpIo to send data to the
2069   specified Src. The IpIo was added previously by IpIoAddIp().
2070 
2071   @param[in, out]  IpIo              Pointer to the pointer of the IP_IO instance.
2072   @param[in]       IpVersion         The version of the IP protocol to use, either
2073                                      IPv4 or IPv6.
2074   @param[in]       Src               The local IP address.
2075 
2076   @return Pointer to the IP protocol can be used for sending purpose and its local
2077           address is the same with Src. NULL if failed.
2078 
2079 **/
2080 IP_IO_IP_INFO *
2081 EFIAPI
2082 IpIoFindSender (
2083   IN OUT IP_IO           **IpIo,
2084   IN     UINT8           IpVersion,
2085   IN     EFI_IP_ADDRESS  *Src
2086   )
2087 {
2088   LIST_ENTRY      *IpIoEntry;
2089   IP_IO           *IpIoPtr;
2090   LIST_ENTRY      *IpInfoEntry;
2091   IP_IO_IP_INFO   *IpInfo;
2092 
2093   if (IpIo == NULL || Src == NULL) {
2094     return NULL;
2095   }
2096 
2097   if ((IpVersion != IP_VERSION_4) && (IpVersion != IP_VERSION_6)) {
2098     return NULL;
2099   }
2100 
2101   NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
2102     IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
2103 
2104     if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {
2105       continue;
2106     }
2107 
2108     NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
2109       IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
2110       if (IpInfo->IpVersion == IP_VERSION_4){
2111 
2112         if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {
2113           *IpIo = IpIoPtr;
2114           return IpInfo;
2115         }
2116 
2117       } else {
2118 
2119         if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {
2120           *IpIo = IpIoPtr;
2121           return IpInfo;
2122         }
2123       }
2124     }
2125   }
2126 
2127   //
2128   // No match.
2129   //
2130   return NULL;
2131 }
2132 
2133 
2134 /**
2135   Get the ICMP error map information.
2136 
2137   The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2138   are not NULL, this routine will fill them.
2139 
2140   @param[in]   IcmpError             IcmpError Type.
2141   @param[in]   IpVersion             The version of the IP protocol to use,
2142                                      either IPv4 or IPv6.
2143   @param[out]  IsHard                If TRUE, indicates that it is a hard error.
2144   @param[out]  Notify                If TRUE, SockError needs to be notified.
2145 
2146   @retval EFI_UNSUPPORTED            Unrecognizable ICMP error code.
2147   @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2148 
2149 **/
2150 EFI_STATUS
2151 EFIAPI
2152 IpIoGetIcmpErrStatus (
2153   IN  UINT8       IcmpError,
2154   IN  UINT8       IpVersion,
2155   OUT BOOLEAN     *IsHard  OPTIONAL,
2156   OUT BOOLEAN     *Notify  OPTIONAL
2157   )
2158 {
2159   if (IpVersion == IP_VERSION_4 ) {
2160     ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);
2161 
2162     if (IsHard != NULL) {
2163       *IsHard = mIcmpErrMap[IcmpError].IsHard;
2164     }
2165 
2166     if (Notify != NULL) {
2167       *Notify = mIcmpErrMap[IcmpError].Notify;
2168     }
2169 
2170     switch (IcmpError) {
2171     case ICMP_ERR_UNREACH_NET:
2172       return  EFI_NETWORK_UNREACHABLE;
2173 
2174     case ICMP_ERR_TIMXCEED_INTRANS:
2175     case ICMP_ERR_TIMXCEED_REASS:
2176     case ICMP_ERR_UNREACH_HOST:
2177       return  EFI_HOST_UNREACHABLE;
2178 
2179     case ICMP_ERR_UNREACH_PROTOCOL:
2180       return  EFI_PROTOCOL_UNREACHABLE;
2181 
2182     case ICMP_ERR_UNREACH_PORT:
2183       return  EFI_PORT_UNREACHABLE;
2184 
2185     case ICMP_ERR_MSGSIZE:
2186     case ICMP_ERR_UNREACH_SRCFAIL:
2187     case ICMP_ERR_QUENCH:
2188     case ICMP_ERR_PARAMPROB:
2189       return  EFI_ICMP_ERROR;
2190 
2191     default:
2192       ASSERT (FALSE);
2193       return EFI_UNSUPPORTED;
2194     }
2195 
2196   } else if (IpVersion == IP_VERSION_6) {
2197 
2198     ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);
2199 
2200     if (IsHard != NULL) {
2201       *IsHard = mIcmp6ErrMap[IcmpError].IsHard;
2202     }
2203 
2204     if (Notify != NULL) {
2205       *Notify = mIcmp6ErrMap[IcmpError].Notify;
2206     }
2207 
2208     switch (IcmpError) {
2209     case ICMP6_ERR_UNREACH_NET:
2210       return EFI_NETWORK_UNREACHABLE;
2211 
2212     case ICMP6_ERR_UNREACH_HOST:
2213     case ICMP6_ERR_TIMXCEED_HOPLIMIT:
2214     case ICMP6_ERR_TIMXCEED_REASS:
2215       return EFI_HOST_UNREACHABLE;
2216 
2217     case ICMP6_ERR_UNREACH_PROTOCOL:
2218       return EFI_PROTOCOL_UNREACHABLE;
2219 
2220     case ICMP6_ERR_UNREACH_PORT:
2221       return EFI_PORT_UNREACHABLE;
2222 
2223     case ICMP6_ERR_PACKAGE_TOOBIG:
2224     case ICMP6_ERR_PARAMPROB_HEADER:
2225     case ICMP6_ERR_PARAMPROB_NEXHEADER:
2226     case ICMP6_ERR_PARAMPROB_IPV6OPTION:
2227       return EFI_ICMP_ERROR;
2228 
2229     default:
2230       ASSERT (FALSE);
2231       return EFI_UNSUPPORTED;
2232     }
2233 
2234   } else {
2235     //
2236     // Should never be here
2237     //
2238     ASSERT (FALSE);
2239     return EFI_UNSUPPORTED;
2240   }
2241 }
2242 
2243 
2244 /**
2245   Refresh the remote peer's Neighbor Cache entries.
2246 
2247   This function is called when the caller needs the IpIo to refresh the existing
2248   IPv6 neighbor cache entries since the neighbor is considered reachable by the
2249   node has recently received a confirmation that packets sent recently to the
2250   neighbor were received by its IP layer.
2251 
2252   @param[in]   IpIo                  Pointer to an IP_IO instance
2253   @param[in]   Neighbor              The IP address of the neighbor
2254   @param[in]   Timeout               Time in 100-ns units that this entry will
2255                                      remain in the neighbor cache. A value of
2256                                      zero means that the entry is permanent.
2257                                      A value of non-zero means that the entry is
2258                                      dynamic and will be deleted after Timeout.
2259 
2260   @retval      EFI_SUCCESS           The operation is completed successfully.
2261   @retval      EFI_NOT_STARTED       The IpIo is not configured.
2262   @retval      EFI_INVALID_PARAMETER Neighbor Address is invalid.
2263   @retval      EFI_NOT_FOUND         The neighbor cache entry is not in the
2264                                      neighbor table.
2265   @retval      EFI_UNSUPPORTED       IP version is IPv4, which doesn't support neighbor cache refresh.
2266   @retval      EFI_OUT_OF_RESOURCES  Failed due to resource limit.
2267 
2268 **/
2269 EFI_STATUS
2270 EFIAPI
2271 IpIoRefreshNeighbor (
2272   IN IP_IO           *IpIo,
2273   IN EFI_IP_ADDRESS  *Neighbor,
2274   IN UINT32          Timeout
2275   )
2276 {
2277   EFI_IP6_PROTOCOL  *Ip;
2278 
2279   if (!IpIo->IsConfigured) {
2280     return EFI_NOT_STARTED;
2281   }
2282 
2283   if (IpIo->IpVersion != IP_VERSION_6) {
2284     return EFI_UNSUPPORTED;
2285   }
2286 
2287   Ip = IpIo->Ip.Ip6;
2288 
2289   return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);
2290 }
2291 
2292