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