1 /** @file
2   IpIo Library.
3 
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2005 - 2009, 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       !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), 0)) {
1033     //
1034     // The source address is not zero and it's not a unicast IP address, discard it.
1035     //
1036     goto CleanUp;
1037   }
1038 
1039   //
1040   // Create a netbuffer representing IPv4 packet
1041   //
1042   Pkt = NetbufFromExt (
1043           (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,
1044           RxData->Ip4RxData.FragmentCount,
1045           0,
1046           0,
1047           IpIoExtFree,
1048           RxData->Ip4RxData.RecycleSignal
1049           );
1050   if (NULL == Pkt) {
1051     goto CleanUp;
1052   }
1053 
1054   //
1055   // Create a net session
1056   //
1057   Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);
1058   Session.Dest.Addr[0]   = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);
1059   Session.IpHdr.Ip4Hdr   = RxData->Ip4RxData.Header;
1060   Session.IpHdrLen       = RxData->Ip4RxData.HeaderLength;
1061   Session.IpVersion      = IP_VERSION_4;
1062   } else {
1063 
1064     if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {
1065       goto CleanUp;
1066     }
1067 
1068     //
1069     // Create a netbuffer representing IPv6 packet
1070     //
1071     Pkt = NetbufFromExt (
1072             (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,
1073             RxData->Ip6RxData.FragmentCount,
1074             0,
1075             0,
1076             IpIoExtFree,
1077             RxData->Ip6RxData.RecycleSignal
1078             );
1079     if (NULL == Pkt) {
1080       goto CleanUp;
1081     }
1082 
1083     //
1084     // Create a net session
1085     //
1086     CopyMem (
1087       &Session.Source,
1088       &RxData->Ip6RxData.Header->SourceAddress,
1089       sizeof(EFI_IPv6_ADDRESS)
1090       );
1091     CopyMem (
1092       &Session.Dest,
1093       &RxData->Ip6RxData.Header->DestinationAddress,
1094       sizeof(EFI_IPv6_ADDRESS)
1095       );
1096     Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;
1097     Session.IpHdrLen     = RxData->Ip6RxData.HeaderLength;
1098     Session.IpVersion    = IP_VERSION_6;
1099   }
1100 
1101   if (EFI_SUCCESS == Status) {
1102 
1103     IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);
1104   } else {
1105     //
1106     // Status is EFI_ICMP_ERROR
1107     //
1108     Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
1109     if (EFI_ERROR (Status)) {
1110       NetbufFree (Pkt);
1111     }
1112   }
1113 
1114   goto Resume;
1115 
1116 CleanUp:
1117 
1118   if (IpIo->IpVersion == IP_VERSION_4){
1119     gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);
1120   } else {
1121     gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);
1122   }
1123 
1124 Resume:
1125 
1126   if (IpIo->IpVersion == IP_VERSION_4){
1127     IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));
1128   } else {
1129     IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));
1130   }
1131 }
1132 
1133 /**
1134   This function add IpIoListenHandlerDpc to the end of the DPC queue.
1135 
1136   @param[in]  Event                The event signaled.
1137   @param[in]  Context              The context passed in by the event notifier.
1138 
1139 **/
1140 VOID
1141 EFIAPI
IpIoListenHandler(IN EFI_EVENT Event,IN VOID * Context)1142 IpIoListenHandler (
1143   IN EFI_EVENT Event,
1144   IN VOID      *Context
1145   )
1146 {
1147   //
1148   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1149   //
1150   QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
1151 }
1152 
1153 
1154 /**
1155   Create a new IP_IO instance.
1156 
1157   This function uses IP4/IP6 service binding protocol in Controller to create
1158   an IP4/IP6 child (aka IP4/IP6 instance).
1159 
1160   @param[in]  Image             The image handle of the driver or application that
1161                                 consumes IP_IO.
1162   @param[in]  Controller        The controller handle that has IP4 or IP6 service
1163                                 binding protocol installed.
1164   @param[in]  IpVersion         The version of the IP protocol to use, either
1165                                 IPv4 or IPv6.
1166 
1167   @return Pointer to a newly created IP_IO instance, or NULL if failed.
1168 
1169 **/
1170 IP_IO *
1171 EFIAPI
IpIoCreate(IN EFI_HANDLE Image,IN EFI_HANDLE Controller,IN UINT8 IpVersion)1172 IpIoCreate (
1173   IN EFI_HANDLE Image,
1174   IN EFI_HANDLE Controller,
1175   IN UINT8      IpVersion
1176   )
1177 {
1178   EFI_STATUS  Status;
1179   IP_IO       *IpIo;
1180   EFI_EVENT   Event;
1181 
1182   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1183 
1184   IpIo = AllocateZeroPool (sizeof (IP_IO));
1185   if (NULL == IpIo) {
1186     return NULL;
1187   }
1188 
1189   InitializeListHead (&(IpIo->PendingSndList));
1190   InitializeListHead (&(IpIo->IpList));
1191   IpIo->Controller  = Controller;
1192   IpIo->Image       = Image;
1193   IpIo->IpVersion   = IpVersion;
1194   Event             = NULL;
1195 
1196   Status = gBS->CreateEvent (
1197                   EVT_NOTIFY_SIGNAL,
1198                   TPL_NOTIFY,
1199                   IpIoListenHandler,
1200                   IpIo,
1201                   &Event
1202                   );
1203   if (EFI_ERROR (Status)) {
1204     goto ReleaseIpIo;
1205   }
1206 
1207   if (IpVersion == IP_VERSION_4) {
1208     IpIo->RcvToken.Ip4Token.Event = Event;
1209   } else {
1210     IpIo->RcvToken.Ip6Token.Event = Event;
1211   }
1212 
1213   //
1214   // Create an IP child and open IP protocol
1215   //
1216   Status = IpIoCreateIpChildOpenProtocol (
1217              Controller,
1218              Image,
1219              &IpIo->ChildHandle,
1220              IpVersion,
1221              (VOID **)&(IpIo->Ip)
1222              );
1223   if (EFI_ERROR (Status)) {
1224     goto ReleaseIpIo;
1225   }
1226 
1227   return IpIo;
1228 
1229 ReleaseIpIo:
1230 
1231   if (Event != NULL) {
1232     gBS->CloseEvent (Event);
1233   }
1234 
1235   gBS->FreePool (IpIo);
1236 
1237   return NULL;
1238 }
1239 
1240 
1241 /**
1242   Open an IP_IO instance for use.
1243 
1244   This function is called after IpIoCreate(). It is used for configuring the IP
1245   instance and register the callbacks and their context data for sending and
1246   receiving IP packets.
1247 
1248   @param[in, out]  IpIo               Pointer to an IP_IO instance that needs
1249                                       to open.
1250   @param[in]       OpenData           The configuration data and callbacks for
1251                                       the IP_IO instance.
1252 
1253   @retval          EFI_SUCCESS        The IP_IO instance opened with OpenData
1254                                       successfully.
1255   @retval          EFI_ACCESS_DENIED  The IP_IO instance is configured, avoid to
1256                                       reopen it.
1257   @retval          Others             Error condition occurred.
1258 
1259 **/
1260 EFI_STATUS
1261 EFIAPI
IpIoOpen(IN OUT IP_IO * IpIo,IN IP_IO_OPEN_DATA * OpenData)1262 IpIoOpen (
1263   IN OUT IP_IO           *IpIo,
1264   IN     IP_IO_OPEN_DATA *OpenData
1265   )
1266 {
1267   EFI_STATUS        Status;
1268   UINT8             IpVersion;
1269 
1270   if (IpIo->IsConfigured) {
1271     return EFI_ACCESS_DENIED;
1272   }
1273 
1274   IpVersion = IpIo->IpVersion;
1275 
1276   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1277 
1278   //
1279   // configure ip
1280   //
1281   if (IpVersion == IP_VERSION_4){
1282     Status = IpIo->Ip.Ip4->Configure (
1283                              IpIo->Ip.Ip4,
1284                              &OpenData->IpConfigData.Ip4CfgData
1285                              );
1286   } else {
1287 
1288     Status = IpIo->Ip.Ip6->Configure (
1289                              IpIo->Ip.Ip6,
1290                              &OpenData->IpConfigData.Ip6CfgData
1291                              );
1292   }
1293 
1294   if (EFI_ERROR (Status)) {
1295     return Status;
1296   }
1297 
1298   //
1299   // @bug To delete the default route entry in this Ip, if it is:
1300   // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1301   // @bug its code
1302   //
1303   if (IpVersion == IP_VERSION_4){
1304     Status = IpIo->Ip.Ip4->Routes (
1305                              IpIo->Ip.Ip4,
1306                              TRUE,
1307                              &mZeroIp4Addr,
1308                              &mZeroIp4Addr,
1309                              &mZeroIp4Addr
1310                              );
1311 
1312     if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
1313       return Status;
1314     }
1315   }
1316 
1317   IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
1318   IpIo->PktSentNotify = OpenData->PktSentNotify;
1319 
1320   IpIo->RcvdContext   = OpenData->RcvdContext;
1321   IpIo->SndContext    = OpenData->SndContext;
1322 
1323   if (IpVersion == IP_VERSION_4){
1324     IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;
1325 
1326     //
1327     // start to listen incoming packet
1328     //
1329     Status = IpIo->Ip.Ip4->Receive (
1330                              IpIo->Ip.Ip4,
1331                              &(IpIo->RcvToken.Ip4Token)
1332                              );
1333     if (EFI_ERROR (Status)) {
1334       IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
1335       goto ErrorExit;
1336     }
1337 
1338   } else {
1339 
1340     IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;
1341     Status = IpIo->Ip.Ip6->Receive (
1342                              IpIo->Ip.Ip6,
1343                              &(IpIo->RcvToken.Ip6Token)
1344                              );
1345     if (EFI_ERROR (Status)) {
1346       IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
1347       goto ErrorExit;
1348     }
1349   }
1350 
1351   IpIo->IsConfigured = TRUE;
1352   InsertTailList (&mActiveIpIoList, &IpIo->Entry);
1353 
1354 ErrorExit:
1355 
1356   return Status;
1357 }
1358 
1359 
1360 /**
1361   Stop an IP_IO instance.
1362 
1363   This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1364   the pending send/receive tokens will be canceled.
1365 
1366   @param[in, out]  IpIo            Pointer to the IP_IO instance that needs to stop.
1367 
1368   @retval          EFI_SUCCESS     The IP_IO instance stopped successfully.
1369   @retval          Others          Error condition occurred.
1370 
1371 **/
1372 EFI_STATUS
1373 EFIAPI
IpIoStop(IN OUT IP_IO * IpIo)1374 IpIoStop (
1375   IN OUT IP_IO *IpIo
1376   )
1377 {
1378   EFI_STATUS        Status;
1379   IP_IO_IP_INFO     *IpInfo;
1380   UINT8             IpVersion;
1381 
1382   if (!IpIo->IsConfigured) {
1383     return EFI_SUCCESS;
1384   }
1385 
1386   IpVersion = IpIo->IpVersion;
1387 
1388   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1389 
1390   //
1391   // Remove the IpIo from the active IpIo list.
1392   //
1393   RemoveEntryList (&IpIo->Entry);
1394 
1395   //
1396   // Configure NULL Ip
1397   //
1398   if (IpVersion == IP_VERSION_4) {
1399     Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
1400   } else {
1401     Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
1402   }
1403   if (EFI_ERROR (Status)) {
1404     return Status;
1405   }
1406 
1407   IpIo->IsConfigured = FALSE;
1408 
1409   //
1410   // Detroy the Ip List used by IpIo
1411   //
1412 
1413   while (!IsListEmpty (&(IpIo->IpList))) {
1414     IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
1415 
1416     IpIoRemoveIp (IpIo, IpInfo);
1417   }
1418 
1419   //
1420   // All pending send tokens should be flushed by reseting the IP instances.
1421   //
1422   ASSERT (IsListEmpty (&IpIo->PendingSndList));
1423 
1424   //
1425   // Close the receive event.
1426   //
1427   if (IpVersion == IP_VERSION_4){
1428     gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);
1429   } else {
1430     gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);
1431   }
1432 
1433   return EFI_SUCCESS;
1434 }
1435 
1436 
1437 /**
1438   Destroy an IP_IO instance.
1439 
1440   This function is paired with IpIoCreate(). The IP_IO will be closed first.
1441   Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1442 
1443   @param[in, out]  IpIo         Pointer to the IP_IO instance that needs to be
1444                                 destroyed.
1445 
1446   @retval          EFI_SUCCESS  The IP_IO instance destroyed successfully.
1447   @retval          Others       Error condition occurred.
1448 
1449 **/
1450 EFI_STATUS
1451 EFIAPI
IpIoDestroy(IN OUT IP_IO * IpIo)1452 IpIoDestroy (
1453   IN OUT IP_IO *IpIo
1454   )
1455 {
1456   //
1457   // Stop the IpIo.
1458   //
1459   IpIoStop (IpIo);
1460 
1461   //
1462   // Close the IP protocol and destroy the child.
1463   //
1464   IpIoCloseProtocolDestroyIpChild (
1465     IpIo->Controller,
1466     IpIo->Image,
1467     IpIo->ChildHandle,
1468     IpIo->IpVersion
1469     );
1470 
1471   gBS->FreePool (IpIo);
1472 
1473   return EFI_SUCCESS;
1474 }
1475 
1476 
1477 /**
1478   Send out an IP packet.
1479 
1480   This function is called after IpIoOpen(). The data to be sent are wrapped in
1481   Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1482   overriden by Sender. Other sending configs, like source address and gateway
1483   address etc., are specified in OverrideData.
1484 
1485   @param[in, out]  IpIo                  Pointer to an IP_IO instance used for sending IP
1486                                          packet.
1487   @param[in, out]  Pkt                   Pointer to the IP packet to be sent.
1488   @param[in]       Sender                The IP protocol instance used for sending.
1489   @param[in]       Context               Optional context data.
1490   @param[in]       NotifyData            Optional notify data.
1491   @param[in]       Dest                  The destination IP address to send this packet to.
1492   @param[in]       OverrideData          The data to override some configuration of the IP
1493                                          instance used for sending.
1494 
1495   @retval          EFI_SUCCESS           The operation is completed successfully.
1496   @retval          EFI_NOT_STARTED       The IpIo is not configured.
1497   @retval          EFI_OUT_OF_RESOURCES  Failed due to resource limit.
1498 
1499 **/
1500 EFI_STATUS
1501 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)1502 IpIoSend (
1503   IN OUT IP_IO          *IpIo,
1504   IN OUT NET_BUF        *Pkt,
1505   IN     IP_IO_IP_INFO  *Sender        OPTIONAL,
1506   IN     VOID           *Context       OPTIONAL,
1507   IN     VOID           *NotifyData    OPTIONAL,
1508   IN     EFI_IP_ADDRESS *Dest,
1509   IN     IP_IO_OVERRIDE *OverrideData  OPTIONAL
1510   )
1511 {
1512   EFI_STATUS        Status;
1513   IP_IO_IP_PROTOCOL Ip;
1514   IP_IO_SEND_ENTRY  *SndEntry;
1515 
1516   ASSERT ((IpIo->IpVersion != IP_VERSION_4) || (Dest != NULL));
1517 
1518   if (!IpIo->IsConfigured) {
1519     return EFI_NOT_STARTED;
1520   }
1521 
1522   Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
1523 
1524   //
1525   // create a new SndEntry
1526   //
1527   SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
1528   if (NULL == SndEntry) {
1529     return EFI_OUT_OF_RESOURCES;
1530   }
1531 
1532   //
1533   // Send this Packet
1534   //
1535   if (IpIo->IpVersion == IP_VERSION_4){
1536     Status = Ip.Ip4->Transmit (
1537                        Ip.Ip4,
1538                        &SndEntry->SndToken.Ip4Token
1539                        );
1540   } else {
1541     Status = Ip.Ip6->Transmit (
1542                        Ip.Ip6,
1543                        &SndEntry->SndToken.Ip6Token
1544                        );
1545   }
1546 
1547   if (EFI_ERROR (Status)) {
1548     IpIoDestroySndEntry (SndEntry);
1549   }
1550 
1551   return Status;
1552 }
1553 
1554 
1555 /**
1556   Cancel the IP transmit token which wraps this Packet.
1557 
1558   @param[in]  IpIo                  Pointer to the IP_IO instance.
1559   @param[in]  Packet                Pointer to the packet of NET_BUF to cancel.
1560 
1561 **/
1562 VOID
1563 EFIAPI
IpIoCancelTxToken(IN IP_IO * IpIo,IN VOID * Packet)1564 IpIoCancelTxToken (
1565   IN IP_IO  *IpIo,
1566   IN VOID   *Packet
1567   )
1568 {
1569   LIST_ENTRY        *Node;
1570   IP_IO_SEND_ENTRY  *SndEntry;
1571   IP_IO_IP_PROTOCOL Ip;
1572 
1573   ASSERT ((IpIo != NULL) && (Packet != NULL));
1574 
1575   NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
1576 
1577     SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
1578 
1579     if (SndEntry->Pkt == Packet) {
1580 
1581       Ip = SndEntry->Ip;
1582 
1583       if (IpIo->IpVersion == IP_VERSION_4) {
1584         Ip.Ip4->Cancel (
1585                   Ip.Ip4,
1586                   &SndEntry->SndToken.Ip4Token
1587                   );
1588       } else {
1589         Ip.Ip6->Cancel (
1590                   Ip.Ip6,
1591                   &SndEntry->SndToken.Ip6Token
1592                   );
1593       }
1594 
1595       break;
1596     }
1597   }
1598 
1599 }
1600 
1601 
1602 /**
1603   Add a new IP instance for sending data.
1604 
1605   The function is used to add the IP_IO to the IP_IO sending list. The caller
1606   can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1607   data.
1608 
1609   @param[in, out]  IpIo               Pointer to a IP_IO instance to add a new IP
1610                                       instance for sending purpose.
1611 
1612   @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1613 
1614 **/
1615 IP_IO_IP_INFO *
1616 EFIAPI
IpIoAddIp(IN OUT IP_IO * IpIo)1617 IpIoAddIp (
1618   IN OUT IP_IO  *IpIo
1619   )
1620 {
1621   EFI_STATUS     Status;
1622   IP_IO_IP_INFO  *IpInfo;
1623   EFI_EVENT      Event;
1624 
1625   ASSERT (IpIo != NULL);
1626 
1627   IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
1628   if (IpInfo == NULL) {
1629     return NULL;
1630   }
1631 
1632   //
1633   // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1634   // instance.
1635   //
1636   InitializeListHead (&IpInfo->Entry);
1637   IpInfo->ChildHandle = NULL;
1638   ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1639   ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1640 
1641   IpInfo->RefCnt    = 1;
1642   IpInfo->IpVersion = IpIo->IpVersion;
1643 
1644   //
1645   // Create the IP instance and open the IP protocol.
1646   //
1647   Status = IpIoCreateIpChildOpenProtocol (
1648              IpIo->Controller,
1649              IpIo->Image,
1650              &IpInfo->ChildHandle,
1651              IpInfo->IpVersion,
1652              (VOID **) &IpInfo->Ip
1653              );
1654   if (EFI_ERROR (Status)) {
1655     goto ReleaseIpInfo;
1656   }
1657 
1658   //
1659   // Create the event for the DummyRcvToken.
1660   //
1661   Status = gBS->CreateEvent (
1662                   EVT_NOTIFY_SIGNAL,
1663                   TPL_NOTIFY,
1664                   IpIoDummyHandler,
1665                   IpInfo,
1666                   &Event
1667                   );
1668   if (EFI_ERROR (Status)) {
1669     goto ReleaseIpChild;
1670   }
1671 
1672   if (IpInfo->IpVersion == IP_VERSION_4) {
1673     IpInfo->DummyRcvToken.Ip4Token.Event = Event;
1674   } else {
1675     IpInfo->DummyRcvToken.Ip6Token.Event = Event;
1676   }
1677 
1678   //
1679   // Link this IpInfo into the IpIo.
1680   //
1681   InsertTailList (&IpIo->IpList, &IpInfo->Entry);
1682 
1683   return IpInfo;
1684 
1685 ReleaseIpChild:
1686 
1687   IpIoCloseProtocolDestroyIpChild (
1688     IpIo->Controller,
1689     IpIo->Image,
1690     IpInfo->ChildHandle,
1691     IpInfo->IpVersion
1692     );
1693 
1694 ReleaseIpInfo:
1695 
1696   gBS->FreePool (IpInfo);
1697 
1698   return NULL;
1699 }
1700 
1701 
1702 /**
1703   Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1704   is not NULL.
1705 
1706   @param[in, out]  IpInfo          Pointer to the IP_IO_IP_INFO instance.
1707   @param[in, out]  IpConfigData    The IP configure data used to configure the IP
1708                                    instance, if NULL the IP instance is reset. If
1709                                    UseDefaultAddress is set to TRUE, and the configure
1710                                    operation succeeds, the default address information
1711                                    is written back in this IpConfigData.
1712 
1713   @retval          EFI_SUCCESS     The IP instance of this IpInfo is configured successfully
1714                                    or no need to reconfigure it.
1715   @retval          Others          Configuration fails.
1716 
1717 **/
1718 EFI_STATUS
1719 EFIAPI
IpIoConfigIp(IN OUT IP_IO_IP_INFO * IpInfo,IN OUT VOID * IpConfigData OPTIONAL)1720 IpIoConfigIp (
1721   IN OUT IP_IO_IP_INFO        *IpInfo,
1722   IN OUT VOID                 *IpConfigData OPTIONAL
1723   )
1724 {
1725   EFI_STATUS         Status;
1726   IP_IO_IP_PROTOCOL  Ip;
1727   UINT8              IpVersion;
1728   EFI_IP4_MODE_DATA  Ip4ModeData;
1729   EFI_IP6_MODE_DATA  Ip6ModeData;
1730 
1731   ASSERT (IpInfo != NULL);
1732 
1733   if (IpInfo->RefCnt > 1) {
1734     //
1735     // This IP instance is shared, don't reconfigure it until it has only one
1736     // consumer. Currently, only the tcp children cloned from their passive parent
1737     // will share the same IP. So this cases only happens while IpConfigData is NULL,
1738     // let the last consumer clean the IP instance.
1739     //
1740     return EFI_SUCCESS;
1741   }
1742 
1743   IpVersion = IpInfo->IpVersion;
1744   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1745 
1746   Ip = IpInfo->Ip;
1747 
1748   if (IpInfo->IpVersion == IP_VERSION_4) {
1749     Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);
1750   } else {
1751     Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);
1752   }
1753 
1754   if (EFI_ERROR (Status)) {
1755     goto OnExit;
1756   }
1757 
1758   if (IpConfigData != NULL) {
1759     if (IpInfo->IpVersion == IP_VERSION_4){
1760 
1761       if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {
1762         Ip.Ip4->GetModeData (
1763                   Ip.Ip4,
1764                   &Ip4ModeData,
1765                   NULL,
1766                   NULL
1767                   );
1768 
1769         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);
1770         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);
1771     }
1772 
1773       CopyMem (
1774         &IpInfo->Addr.Addr,
1775         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,
1776         sizeof (IP4_ADDR)
1777         );
1778       CopyMem (
1779         &IpInfo->PreMask.SubnetMask,
1780         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,
1781         sizeof (IP4_ADDR)
1782         );
1783 
1784       Status = Ip.Ip4->Receive (
1785                          Ip.Ip4,
1786                          &IpInfo->DummyRcvToken.Ip4Token
1787                          );
1788     if (EFI_ERROR (Status)) {
1789       Ip.Ip4->Configure (Ip.Ip4, NULL);
1790     }
1791   } else {
1792     Ip.Ip6->GetModeData (
1793               Ip.Ip6,
1794               &Ip6ModeData,
1795               NULL,
1796               NULL
1797               );
1798 
1799       if (Ip6ModeData.IsConfigured) {
1800         CopyMem (
1801           &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,
1802           &Ip6ModeData.ConfigData.StationAddress,
1803           sizeof (EFI_IPv6_ADDRESS)
1804           );
1805 
1806         if (Ip6ModeData.AddressList != NULL) {
1807           FreePool (Ip6ModeData.AddressList);
1808         }
1809 
1810         if (Ip6ModeData.GroupTable != NULL) {
1811           FreePool (Ip6ModeData.GroupTable);
1812         }
1813 
1814         if (Ip6ModeData.RouteTable != NULL) {
1815           FreePool (Ip6ModeData.RouteTable);
1816         }
1817 
1818         if (Ip6ModeData.NeighborCache != NULL) {
1819           FreePool (Ip6ModeData.NeighborCache);
1820         }
1821 
1822         if (Ip6ModeData.PrefixTable != NULL) {
1823           FreePool (Ip6ModeData.PrefixTable);
1824         }
1825 
1826         if (Ip6ModeData.IcmpTypeList != NULL) {
1827           FreePool (Ip6ModeData.IcmpTypeList);
1828         }
1829 
1830       } else {
1831         Status = EFI_NO_MAPPING;
1832         goto OnExit;
1833       }
1834 
1835       CopyMem (
1836         &IpInfo->Addr,
1837         &Ip6ModeData.ConfigData.StationAddress,
1838         sizeof (EFI_IPv6_ADDRESS)
1839         );
1840 
1841       Status = Ip.Ip6->Receive (
1842                          Ip.Ip6,
1843                          &IpInfo->DummyRcvToken.Ip6Token
1844                          );
1845       if (EFI_ERROR (Status)) {
1846         Ip.Ip6->Configure (Ip.Ip6, NULL);
1847       }
1848     }
1849   } else {
1850     //
1851     // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1852     //
1853     ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1854     ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1855   }
1856 
1857 OnExit:
1858 
1859   return Status;
1860 }
1861 
1862 
1863 /**
1864   Destroy an IP instance maintained in IpIo->IpList for
1865   sending purpose.
1866 
1867   This function pairs with IpIoAddIp(). The IpInfo is previously created by
1868   IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1869   will be dstroyed if the RefCnt is zero.
1870 
1871   @param[in]  IpIo                  Pointer to the IP_IO instance.
1872   @param[in]  IpInfo                Pointer to the IpInfo to be removed.
1873 
1874 **/
1875 VOID
1876 EFIAPI
IpIoRemoveIp(IN IP_IO * IpIo,IN IP_IO_IP_INFO * IpInfo)1877 IpIoRemoveIp (
1878   IN IP_IO            *IpIo,
1879   IN IP_IO_IP_INFO    *IpInfo
1880   )
1881 {
1882 
1883   UINT8               IpVersion;
1884 
1885   ASSERT (IpInfo->RefCnt > 0);
1886 
1887   NET_PUT_REF (IpInfo);
1888 
1889   if (IpInfo->RefCnt > 0) {
1890 
1891     return;
1892   }
1893 
1894   IpVersion = IpIo->IpVersion;
1895 
1896   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1897 
1898   RemoveEntryList (&IpInfo->Entry);
1899 
1900   if (IpVersion == IP_VERSION_4){
1901     IpInfo->Ip.Ip4->Configure (
1902                       IpInfo->Ip.Ip4,
1903                       NULL
1904                       );
1905     IpIoCloseProtocolDestroyIpChild (
1906       IpIo->Controller,
1907       IpIo->Image,
1908       IpInfo->ChildHandle,
1909       IP_VERSION_4
1910       );
1911 
1912     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);
1913 
1914   } else {
1915 
1916     IpInfo->Ip.Ip6->Configure (
1917                       IpInfo->Ip.Ip6,
1918                       NULL
1919                       );
1920 
1921     IpIoCloseProtocolDestroyIpChild (
1922       IpIo->Controller,
1923       IpIo->Image,
1924       IpInfo->ChildHandle,
1925       IP_VERSION_6
1926       );
1927 
1928     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);
1929   }
1930 
1931   FreePool (IpInfo);
1932 }
1933 
1934 
1935 /**
1936   Find the first IP protocol maintained in IpIo whose local
1937   address is the same as Src.
1938 
1939   This function is called when the caller needs the IpIo to send data to the
1940   specified Src. The IpIo was added previously by IpIoAddIp().
1941 
1942   @param[in, out]  IpIo              Pointer to the pointer of the IP_IO instance.
1943   @param[in]       IpVersion         The version of the IP protocol to use, either
1944                                      IPv4 or IPv6.
1945   @param[in]       Src               The local IP address.
1946 
1947   @return Pointer to the IP protocol can be used for sending purpose and its local
1948           address is the same with Src.
1949 
1950 **/
1951 IP_IO_IP_INFO *
1952 EFIAPI
IpIoFindSender(IN OUT IP_IO ** IpIo,IN UINT8 IpVersion,IN EFI_IP_ADDRESS * Src)1953 IpIoFindSender (
1954   IN OUT IP_IO           **IpIo,
1955   IN     UINT8           IpVersion,
1956   IN     EFI_IP_ADDRESS  *Src
1957   )
1958 {
1959   LIST_ENTRY      *IpIoEntry;
1960   IP_IO           *IpIoPtr;
1961   LIST_ENTRY      *IpInfoEntry;
1962   IP_IO_IP_INFO   *IpInfo;
1963 
1964   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1965 
1966   NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
1967     IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
1968 
1969     if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {
1970       continue;
1971     }
1972 
1973     NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
1974       IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
1975       if (IpInfo->IpVersion == IP_VERSION_4){
1976 
1977         if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {
1978           *IpIo = IpIoPtr;
1979           return IpInfo;
1980         }
1981 
1982       } else {
1983 
1984         if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {
1985           *IpIo = IpIoPtr;
1986           return IpInfo;
1987         }
1988       }
1989 
1990     }
1991   }
1992 
1993   //
1994   // No match.
1995   //
1996   return NULL;
1997 }
1998 
1999 
2000 /**
2001   Get the ICMP error map information.
2002 
2003   The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2004   are not NULL, this routine will fill them.
2005 
2006   @param[in]   IcmpError             IcmpError Type.
2007   @param[in]   IpVersion             The version of the IP protocol to use,
2008                                      either IPv4 or IPv6.
2009   @param[out]  IsHard                If TRUE, indicates that it is a hard error.
2010   @param[out]  Notify                If TRUE, SockError needs to be notified.
2011 
2012   @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2013 
2014 **/
2015 EFI_STATUS
2016 EFIAPI
IpIoGetIcmpErrStatus(IN UINT8 IcmpError,IN UINT8 IpVersion,OUT BOOLEAN * IsHard OPTIONAL,OUT BOOLEAN * Notify OPTIONAL)2017 IpIoGetIcmpErrStatus (
2018   IN  UINT8       IcmpError,
2019   IN  UINT8       IpVersion,
2020   OUT BOOLEAN     *IsHard  OPTIONAL,
2021   OUT BOOLEAN     *Notify  OPTIONAL
2022   )
2023 {
2024   if (IpVersion == IP_VERSION_4 ) {
2025     ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);
2026 
2027     if (IsHard != NULL) {
2028       *IsHard = mIcmpErrMap[IcmpError].IsHard;
2029     }
2030 
2031     if (Notify != NULL) {
2032       *Notify = mIcmpErrMap[IcmpError].Notify;
2033     }
2034 
2035     switch (IcmpError) {
2036     case ICMP_ERR_UNREACH_NET:
2037       return  EFI_NETWORK_UNREACHABLE;
2038 
2039     case ICMP_ERR_TIMXCEED_INTRANS:
2040     case ICMP_ERR_TIMXCEED_REASS:
2041     case ICMP_ERR_UNREACH_HOST:
2042       return  EFI_HOST_UNREACHABLE;
2043 
2044     case ICMP_ERR_UNREACH_PROTOCOL:
2045       return  EFI_PROTOCOL_UNREACHABLE;
2046 
2047     case ICMP_ERR_UNREACH_PORT:
2048       return  EFI_PORT_UNREACHABLE;
2049 
2050     case ICMP_ERR_MSGSIZE:
2051     case ICMP_ERR_UNREACH_SRCFAIL:
2052     case ICMP_ERR_QUENCH:
2053     case ICMP_ERR_PARAMPROB:
2054       return  EFI_ICMP_ERROR;
2055 
2056     default:
2057       ASSERT (FALSE);
2058       return EFI_UNSUPPORTED;
2059     }
2060 
2061   } else if (IpVersion == IP_VERSION_6) {
2062 
2063     ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);
2064 
2065     if (IsHard != NULL) {
2066       *IsHard = mIcmp6ErrMap[IcmpError].IsHard;
2067     }
2068 
2069     if (Notify != NULL) {
2070       *Notify = mIcmp6ErrMap[IcmpError].Notify;
2071     }
2072 
2073     switch (IcmpError) {
2074     case ICMP6_ERR_UNREACH_NET:
2075       return EFI_NETWORK_UNREACHABLE;
2076 
2077     case ICMP6_ERR_UNREACH_HOST:
2078     case ICMP6_ERR_TIMXCEED_HOPLIMIT:
2079     case ICMP6_ERR_TIMXCEED_REASS:
2080       return EFI_HOST_UNREACHABLE;
2081 
2082     case ICMP6_ERR_UNREACH_PROTOCOL:
2083       return EFI_PROTOCOL_UNREACHABLE;
2084 
2085     case ICMP6_ERR_UNREACH_PORT:
2086       return EFI_PORT_UNREACHABLE;
2087 
2088     case ICMP6_ERR_PACKAGE_TOOBIG:
2089     case ICMP6_ERR_PARAMPROB_HEADER:
2090     case ICMP6_ERR_PARAMPROB_NEXHEADER:
2091     case ICMP6_ERR_PARAMPROB_IPV6OPTION:
2092       return EFI_ICMP_ERROR;
2093 
2094     default:
2095       ASSERT (FALSE);
2096       return EFI_UNSUPPORTED;
2097     }
2098 
2099   } else {
2100     //
2101     // Should never be here
2102     //
2103     ASSERT (FALSE);
2104     return EFI_UNSUPPORTED;
2105   }
2106 }
2107 
2108 
2109 /**
2110   Refresh the remote peer's Neighbor Cache entries.
2111 
2112   This function is called when the caller needs the IpIo to refresh the existing
2113   IPv6 neighbor cache entries since the neighbor is considered reachable by the
2114   node has recently received a confirmation that packets sent recently to the
2115   neighbor were received by its IP layer.
2116 
2117   @param[in]   IpIo                  Pointer to an IP_IO instance
2118   @param[in]   Neighbor              The IP address of the neighbor
2119   @param[in]   Timeout               Time in 100-ns units that this entry will
2120                                      remain in the neighbor cache. A value of
2121                                      zero means that the entry is permanent.
2122                                      A value of non-zero means that the entry is
2123                                      dynamic and will be deleted after Timeout.
2124 
2125   @retval      EFI_SUCCESS           The operation is completed successfully.
2126   @retval      EFI_NOT_STARTED       The IpIo is not configured.
2127   @retval      EFI_INVALID_PARAMETER Neighbor Address is invalid.
2128   @retval      EFI_NOT_FOUND         The neighbor cache entry is not in the
2129                                      neighbor table.
2130   @retval      EFI_OUT_OF_RESOURCES  Failed due to resource limit.
2131 
2132 **/
2133 EFI_STATUS
IpIoRefreshNeighbor(IN IP_IO * IpIo,IN EFI_IP_ADDRESS * Neighbor,IN UINT32 Timeout)2134 IpIoRefreshNeighbor (
2135   IN IP_IO           *IpIo,
2136   IN EFI_IP_ADDRESS  *Neighbor,
2137   IN UINT32          Timeout
2138   )
2139 {
2140   EFI_IP6_PROTOCOL  *Ip;
2141 
2142   if (!IpIo->IsConfigured || IpIo->IpVersion != IP_VERSION_6) {
2143     return EFI_NOT_STARTED;
2144   }
2145 
2146   Ip = IpIo->Ip.Ip6;
2147 
2148   return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);
2149 }
2150 
2151