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