]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
Code clean up in NetLib:
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
1 /** @file
2 IpIo Library.
3
4 Copyright (c) 2005 - 2009, Intel Corporation.<BR>
5 All rights reserved. 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 IpIoExtFree (
591 IN VOID *Event
592 )
593 {
594 gBS->SignalEvent ((EFI_EVENT) Event);
595 }
596
597
598 /**
599 Create a send entry to wrap a packet before sending
600 out it through IP.
601
602 @param[in, out] IpIo Pointer to the IP_IO instance.
603 @param[in, out] Pkt Pointer to the packet.
604 @param[in] Sender Pointer to the IP sender.
605 @param[in] Context Pointer to the context.
606 @param[in] NotifyData Pointer to the notify data.
607 @param[in] Dest Pointer to the destination IP address.
608 @param[in] Override Pointer to the overriden IP_IO data.
609
610 @return Pointer to the data structure created to wrap the packet. If NULL,
611 @return resource limit occurred.
612
613 **/
614 IP_IO_SEND_ENTRY *
615 IpIoCreateSndEntry (
616 IN OUT IP_IO *IpIo,
617 IN OUT NET_BUF *Pkt,
618 IN VOID *Sender,
619 IN VOID *Context OPTIONAL,
620 IN VOID *NotifyData OPTIONAL,
621 IN EFI_IP_ADDRESS *Dest OPTIONAL,
622 IN IP_IO_OVERRIDE *Override
623 )
624 {
625 IP_IO_SEND_ENTRY *SndEntry;
626 EFI_EVENT Event;
627 EFI_STATUS Status;
628 NET_FRAGMENT *ExtFragment;
629 UINT32 FragmentCount;
630 IP_IO_OVERRIDE *OverrideData;
631 IP_IO_IP_TX_DATA *TxData;
632 EFI_IP4_TRANSMIT_DATA *Ip4TxData;
633 EFI_IP6_TRANSMIT_DATA *Ip6TxData;
634
635 if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {
636 return NULL;
637 }
638
639 Event = NULL;
640 TxData = NULL;
641 OverrideData = NULL;
642
643 //
644 // Allocate resource for SndEntry
645 //
646 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
647 if (NULL == SndEntry) {
648 return NULL;
649 }
650
651 Status = gBS->CreateEvent (
652 EVT_NOTIFY_SIGNAL,
653 TPL_NOTIFY,
654 IpIoTransmitHandler,
655 SndEntry,
656 &Event
657 );
658 if (EFI_ERROR (Status)) {
659 goto ON_ERROR;
660 }
661
662 FragmentCount = Pkt->BlockOpNum;
663
664 //
665 // Allocate resource for TxData
666 //
667 TxData = (IP_IO_IP_TX_DATA *) AllocatePool (
668 sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)
669 );
670
671 if (NULL == TxData) {
672 goto ON_ERROR;
673 }
674
675 //
676 // Build a fragment table to contain the fragments in the packet.
677 //
678 if (IpIo->IpVersion == IP_VERSION_4) {
679 ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;
680 } else {
681 ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;
682 }
683
684 NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);
685
686
687 //
688 // Allocate resource for OverrideData if needed
689 //
690 if (NULL != Override) {
691
692 OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);
693 if (NULL == OverrideData) {
694 goto ON_ERROR;
695 }
696 }
697
698 //
699 // Set other fields of TxData except the fragment table
700 //
701 if (IpIo->IpVersion == IP_VERSION_4) {
702
703 Ip4TxData = &TxData->Ip4TxData;
704
705 CopyMem (&Ip4TxData->DestinationAddress, Dest, sizeof (EFI_IPv4_ADDRESS));
706
707 Ip4TxData->OverrideData = &OverrideData->Ip4OverrideData;
708 Ip4TxData->OptionsLength = 0;
709 Ip4TxData->OptionsBuffer = NULL;
710 Ip4TxData->TotalDataLength = Pkt->TotalSize;
711 Ip4TxData->FragmentCount = FragmentCount;
712
713 //
714 // Set the fields of SndToken
715 //
716 SndEntry->SndToken.Ip4Token.Event = Event;
717 SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;
718 } else {
719
720 Ip6TxData = &TxData->Ip6TxData;
721
722 if (Dest != NULL) {
723 CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));
724 } else {
725 ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
726 }
727
728 Ip6TxData->OverrideData = &OverrideData->Ip6OverrideData;
729 Ip6TxData->DataLength = Pkt->TotalSize;
730 Ip6TxData->FragmentCount = FragmentCount;
731 Ip6TxData->ExtHdrsLength = 0;
732 Ip6TxData->ExtHdrs = NULL;
733
734 //
735 // Set the fields of SndToken
736 //
737 SndEntry->SndToken.Ip6Token.Event = Event;
738 SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;
739 }
740
741 //
742 // Set the fields of SndEntry
743 //
744 SndEntry->IpIo = IpIo;
745 SndEntry->Ip = Sender;
746 SndEntry->Context = Context;
747 SndEntry->NotifyData = NotifyData;
748
749 SndEntry->Pkt = Pkt;
750 NET_GET_REF (Pkt);
751
752 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
753
754 return SndEntry;
755
756 ON_ERROR:
757
758 if (OverrideData != NULL) {
759 FreePool (OverrideData);
760 }
761
762 if (TxData != NULL) {
763 FreePool (TxData);
764 }
765
766 if (SndEntry != NULL) {
767 FreePool (SndEntry);
768 }
769
770 if (Event != NULL) {
771 gBS->CloseEvent (Event);
772 }
773
774 return NULL;
775 }
776
777
778 /**
779 Destroy the SndEntry.
780
781 This function pairs with IpIoCreateSndEntry().
782
783 @param[in] SndEntry Pointer to the send entry to be destroyed.
784
785 **/
786 VOID
787 IpIoDestroySndEntry (
788 IN IP_IO_SEND_ENTRY *SndEntry
789 )
790 {
791 EFI_EVENT Event;
792 IP_IO_IP_TX_DATA *TxData;
793 IP_IO_OVERRIDE *Override;
794
795 if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {
796 Event = SndEntry->SndToken.Ip4Token.Event;
797 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;
798 Override = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;
799 } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {
800 Event = SndEntry->SndToken.Ip6Token.Event;
801 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;
802 Override = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;
803 } else {
804 return ;
805 }
806
807 gBS->CloseEvent (Event);
808
809 FreePool (TxData);
810
811 if (NULL != Override) {
812 FreePool (Override);
813 }
814
815 NetbufFree (SndEntry->Pkt);
816
817 RemoveEntryList (&SndEntry->Entry);
818
819 FreePool (SndEntry);
820 }
821
822
823 /**
824 Notify function for IP transmit token.
825
826 @param[in] Context The context passed in by the event notifier.
827
828 **/
829 VOID
830 EFIAPI
831 IpIoTransmitHandlerDpc (
832 IN VOID *Context
833 )
834 {
835 IP_IO *IpIo;
836 IP_IO_SEND_ENTRY *SndEntry;
837 EFI_STATUS Status;
838
839 SndEntry = (IP_IO_SEND_ENTRY *) Context;
840
841 IpIo = SndEntry->IpIo;
842
843 if (IpIo->IpVersion == IP_VERSION_4) {
844 Status = SndEntry->SndToken.Ip4Token.Status;
845 } else if (IpIo->IpVersion == IP_VERSION_6){
846 Status = SndEntry->SndToken.Ip6Token.Status;
847 } else {
848 return ;
849 }
850
851 if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {
852 IpIo->PktSentNotify (
853 Status,
854 SndEntry->Context,
855 SndEntry->Ip,
856 SndEntry->NotifyData
857 );
858 }
859
860 IpIoDestroySndEntry (SndEntry);
861 }
862
863
864 /**
865 Notify function for IP transmit token.
866
867 @param[in] Event The event signaled.
868 @param[in] Context The context passed in by the event notifier.
869
870 **/
871 VOID
872 EFIAPI
873 IpIoTransmitHandler (
874 IN EFI_EVENT Event,
875 IN VOID *Context
876 )
877 {
878 //
879 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
880 //
881 QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
882 }
883
884
885 /**
886 The dummy handler for the dummy IP receive token.
887
888 @param[in] Context The context passed in by the event notifier.
889
890 **/
891 VOID
892 EFIAPI
893 IpIoDummyHandlerDpc (
894 IN VOID *Context
895 )
896 {
897 IP_IO_IP_INFO *IpInfo;
898 EFI_STATUS Status;
899 EFI_EVENT RecycleEvent;
900
901 IpInfo = (IP_IO_IP_INFO *) Context;
902
903 if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {
904 return ;
905 }
906
907 RecycleEvent = NULL;
908
909 if (IpInfo->IpVersion == IP_VERSION_4) {
910 Status = IpInfo->DummyRcvToken.Ip4Token.Status;
911
912 if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {
913 RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;
914 }
915 } else {
916 Status = IpInfo->DummyRcvToken.Ip6Token.Status;
917
918 if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {
919 RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;
920 }
921 }
922
923
924
925 if (EFI_ABORTED == Status) {
926 //
927 // The reception is actively aborted by the consumer, directly return.
928 //
929 return;
930 } else if (EFI_SUCCESS == Status) {
931 //
932 // Recycle the RxData.
933 //
934 ASSERT (RecycleEvent != NULL);
935
936 gBS->SignalEvent (RecycleEvent);
937 }
938
939 //
940 // Continue the receive.
941 //
942 if (IpInfo->IpVersion == IP_VERSION_4) {
943 ((EFI_IP4_PROTOCOL *) (IpInfo->Ip))->Receive (
944 (EFI_IP4_PROTOCOL *) (IpInfo->Ip),
945 &IpInfo->DummyRcvToken.Ip4Token
946 );
947 } else {
948 ((EFI_IP6_PROTOCOL *) (IpInfo->Ip))->Receive (
949 (EFI_IP6_PROTOCOL *) (IpInfo->Ip),
950 &IpInfo->DummyRcvToken.Ip6Token
951 );
952 }
953 }
954
955
956 /**
957 This function add IpIoDummyHandlerDpc to the end of the DPC queue.
958
959 @param[in] Event The event signaled.
960 @param[in] Context The context passed in by the event notifier.
961
962 **/
963 VOID
964 EFIAPI
965 IpIoDummyHandler (
966 IN EFI_EVENT Event,
967 IN VOID *Context
968 )
969 {
970 //
971 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
972 //
973 QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
974 }
975
976
977 /**
978 Notify function for the IP receive token, used to process
979 the received IP packets.
980
981 @param[in] Context The context passed in by the event notifier.
982
983 **/
984 VOID
985 EFIAPI
986 IpIoListenHandlerDpc (
987 IN VOID *Context
988 )
989 {
990 IP_IO *IpIo;
991 EFI_STATUS Status;
992 IP_IO_IP_RX_DATA *RxData;
993 VOID *Ip;
994 EFI_NET_SESSION_DATA Session;
995 NET_BUF *Pkt;
996
997 IpIo = (IP_IO *) Context;
998 Ip = IpIo->Ip;
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 ((EFI_IP4_PROTOCOL *) Ip)->Receive (Ip, &(IpIo->RcvToken.Ip4Token));
1128 } else {
1129 ((EFI_IP6_PROTOCOL *) Ip)->Receive (Ip, &(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
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
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
1262 IpIoOpen (
1263 IN OUT IP_IO *IpIo,
1264 IN IP_IO_OPEN_DATA *OpenData
1265 )
1266 {
1267 EFI_STATUS Status;
1268 VOID *Ip;
1269 UINT8 IpVersion;
1270
1271 if (IpIo->IsConfigured) {
1272 return EFI_ACCESS_DENIED;
1273 }
1274
1275 IpVersion = IpIo->IpVersion;
1276
1277 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1278
1279 Ip = IpIo->Ip;
1280
1281 //
1282 // configure ip
1283 //
1284 if (IpVersion == IP_VERSION_4){
1285 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure (
1286 (EFI_IP4_PROTOCOL *) Ip,
1287 &OpenData->IpConfigData.Ip4CfgData
1288 );
1289 } else {
1290
1291 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure (
1292 (EFI_IP6_PROTOCOL *) Ip,
1293 &OpenData->IpConfigData.Ip6CfgData
1294 );
1295 }
1296
1297 if (EFI_ERROR (Status)) {
1298 return Status;
1299 }
1300
1301 //
1302 // @bug To delete the default route entry in this Ip, if it is:
1303 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1304 // @bug its code
1305 //
1306 if (IpVersion == IP_VERSION_4){
1307 Status = ((EFI_IP4_PROTOCOL *) Ip)->Routes (
1308 (EFI_IP4_PROTOCOL *) Ip,
1309 TRUE,
1310 &mZeroIp4Addr,
1311 &mZeroIp4Addr,
1312 &mZeroIp4Addr
1313 );
1314
1315 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
1316 return Status;
1317 }
1318 }
1319
1320 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
1321 IpIo->PktSentNotify = OpenData->PktSentNotify;
1322
1323 IpIo->RcvdContext = OpenData->RcvdContext;
1324 IpIo->SndContext = OpenData->SndContext;
1325
1326 if (IpVersion == IP_VERSION_4){
1327 IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;
1328
1329 //
1330 // start to listen incoming packet
1331 //
1332 Status = ((EFI_IP4_PROTOCOL *) Ip)->Receive (
1333 (EFI_IP4_PROTOCOL *) Ip,
1334 &(IpIo->RcvToken.Ip4Token)
1335 );
1336 if (EFI_ERROR (Status)) {
1337 ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, NULL);
1338 goto ErrorExit;
1339 }
1340
1341 } else {
1342
1343 IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;
1344 Status = ((EFI_IP6_PROTOCOL *) Ip)->Receive (
1345 (EFI_IP6_PROTOCOL *) Ip,
1346 &(IpIo->RcvToken.Ip6Token)
1347 );
1348 if (EFI_ERROR (Status)) {
1349 ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);
1350 goto ErrorExit;
1351 }
1352 }
1353
1354 IpIo->IsConfigured = TRUE;
1355 InsertTailList (&mActiveIpIoList, &IpIo->Entry);
1356
1357 ErrorExit:
1358
1359 return Status;
1360 }
1361
1362
1363 /**
1364 Stop an IP_IO instance.
1365
1366 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1367 the pending send/receive tokens will be canceled.
1368
1369 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
1370
1371 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
1372 @retval Others Error condition occurred.
1373
1374 **/
1375 EFI_STATUS
1376 EFIAPI
1377 IpIoStop (
1378 IN OUT IP_IO *IpIo
1379 )
1380 {
1381 EFI_STATUS Status;
1382 VOID *Ip;
1383 IP_IO_IP_INFO *IpInfo;
1384 UINT8 IpVersion;
1385
1386 if (!IpIo->IsConfigured) {
1387 return EFI_SUCCESS;
1388 }
1389
1390 IpVersion = IpIo->IpVersion;
1391
1392 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1393
1394 //
1395 // Remove the IpIo from the active IpIo list.
1396 //
1397 RemoveEntryList (&IpIo->Entry);
1398
1399 Ip = IpIo->Ip;
1400
1401 //
1402 // Configure NULL Ip
1403 //
1404 if (IpVersion == IP_VERSION_4) {
1405 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, NULL);
1406 } else {
1407 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);
1408 }
1409 if (EFI_ERROR (Status)) {
1410 return Status;
1411 }
1412
1413 IpIo->IsConfigured = FALSE;
1414
1415 //
1416 // Detroy the Ip List used by IpIo
1417 //
1418
1419 while (!IsListEmpty (&(IpIo->IpList))) {
1420 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
1421
1422 IpIoRemoveIp (IpIo, IpInfo);
1423 }
1424
1425 //
1426 // All pending send tokens should be flushed by reseting the IP instances.
1427 //
1428 ASSERT (IsListEmpty (&IpIo->PendingSndList));
1429
1430 //
1431 // Close the receive event.
1432 //
1433 if (IpVersion == IP_VERSION_4){
1434 gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);
1435 } else {
1436 gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);
1437 }
1438
1439 return EFI_SUCCESS;
1440 }
1441
1442
1443 /**
1444 Destroy an IP_IO instance.
1445
1446 This function is paired with IpIoCreate(). The IP_IO will be closed first.
1447 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1448
1449 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
1450 destroyed.
1451
1452 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
1453 @retval Others Error condition occurred.
1454
1455 **/
1456 EFI_STATUS
1457 EFIAPI
1458 IpIoDestroy (
1459 IN OUT IP_IO *IpIo
1460 )
1461 {
1462 //
1463 // Stop the IpIo.
1464 //
1465 IpIoStop (IpIo);
1466
1467 //
1468 // Close the IP protocol and destroy the child.
1469 //
1470 IpIoCloseProtocolDestroyIpChild (
1471 IpIo->Controller,
1472 IpIo->Image,
1473 IpIo->ChildHandle,
1474 IpIo->IpVersion
1475 );
1476
1477 gBS->FreePool (IpIo);
1478
1479 return EFI_SUCCESS;
1480 }
1481
1482
1483 /**
1484 Send out an IP packet.
1485
1486 This function is called after IpIoOpen(). The data to be sent are wrapped in
1487 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1488 overriden by Sender. Other sending configs, like source address and gateway
1489 address etc., are specified in OverrideData.
1490
1491 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1492 packet.
1493 @param[in, out] Pkt Pointer to the IP packet to be sent.
1494 @param[in] Sender The IP protocol instance used for sending.
1495 @param[in] Context Optional context data.
1496 @param[in] NotifyData Optional notify data.
1497 @param[in] Dest The destination IP address to send this packet to.
1498 @param[in] OverrideData The data to override some configuration of the IP
1499 instance used for sending.
1500
1501 @retval EFI_SUCCESS The operation is completed successfully.
1502 @retval EFI_NOT_STARTED The IpIo is not configured.
1503 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1504
1505 **/
1506 EFI_STATUS
1507 EFIAPI
1508 IpIoSend (
1509 IN OUT IP_IO *IpIo,
1510 IN OUT NET_BUF *Pkt,
1511 IN IP_IO_IP_INFO *Sender OPTIONAL,
1512 IN VOID *Context OPTIONAL,
1513 IN VOID *NotifyData OPTIONAL,
1514 IN EFI_IP_ADDRESS *Dest,
1515 IN IP_IO_OVERRIDE *OverrideData OPTIONAL
1516 )
1517 {
1518 EFI_STATUS Status;
1519 VOID *Ip;
1520 IP_IO_SEND_ENTRY *SndEntry;
1521
1522 ASSERT ((IpIo->IpVersion != IP_VERSION_4) || (Dest != NULL));
1523
1524 if (!IpIo->IsConfigured) {
1525 return EFI_NOT_STARTED;
1526 }
1527
1528 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
1529
1530 //
1531 // create a new SndEntry
1532 //
1533 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
1534 if (NULL == SndEntry) {
1535 return EFI_OUT_OF_RESOURCES;
1536 }
1537
1538 //
1539 // Send this Packet
1540 //
1541 if (IpIo->IpVersion == IP_VERSION_4){
1542 Status = ((EFI_IP4_PROTOCOL *) Ip)->Transmit (
1543 (EFI_IP4_PROTOCOL *) Ip,
1544 &SndEntry->SndToken.Ip4Token
1545 );
1546 } else {
1547 Status = ((EFI_IP6_PROTOCOL *) Ip)->Transmit (
1548 (EFI_IP6_PROTOCOL *) Ip,
1549 &SndEntry->SndToken.Ip6Token
1550 );
1551 }
1552
1553 if (EFI_ERROR (Status)) {
1554 IpIoDestroySndEntry (SndEntry);
1555 }
1556
1557 return Status;
1558 }
1559
1560
1561 /**
1562 Cancel the IP transmit token which wraps this Packet.
1563
1564 @param[in] IpIo Pointer to the IP_IO instance.
1565 @param[in] Packet Pointer to the packet of NET_BUF to cancel.
1566
1567 **/
1568 VOID
1569 EFIAPI
1570 IpIoCancelTxToken (
1571 IN IP_IO *IpIo,
1572 IN VOID *Packet
1573 )
1574 {
1575 LIST_ENTRY *Node;
1576 IP_IO_SEND_ENTRY *SndEntry;
1577 VOID *Ip;
1578
1579 ASSERT ((IpIo != NULL) && (Packet != NULL));
1580
1581 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
1582
1583 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
1584
1585 if (SndEntry->Pkt == Packet) {
1586
1587 Ip = SndEntry->Ip;
1588
1589 if (IpIo->IpVersion == IP_VERSION_4) {
1590 ((EFI_IP4_PROTOCOL *) Ip)->Cancel (
1591 (EFI_IP4_PROTOCOL *) Ip,
1592 &SndEntry->SndToken.Ip4Token
1593 );
1594 } else {
1595 ((EFI_IP6_PROTOCOL *) Ip)->Cancel (
1596 (EFI_IP6_PROTOCOL *) Ip,
1597 &SndEntry->SndToken.Ip6Token
1598 );
1599 }
1600
1601 break;
1602 }
1603 }
1604
1605 }
1606
1607
1608 /**
1609 Add a new IP instance for sending data.
1610
1611 The function is used to add the IP_IO to the IP_IO sending list. The caller
1612 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1613 data.
1614
1615 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
1616 instance for sending purpose.
1617
1618 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1619
1620 **/
1621 IP_IO_IP_INFO *
1622 EFIAPI
1623 IpIoAddIp (
1624 IN OUT IP_IO *IpIo
1625 )
1626 {
1627 EFI_STATUS Status;
1628 IP_IO_IP_INFO *IpInfo;
1629 EFI_EVENT Event;
1630
1631 ASSERT (IpIo != NULL);
1632
1633 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
1634 if (IpInfo == NULL) {
1635 return NULL;
1636 }
1637
1638 //
1639 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1640 // instance.
1641 //
1642 InitializeListHead (&IpInfo->Entry);
1643 IpInfo->ChildHandle = NULL;
1644 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1645 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1646
1647 IpInfo->RefCnt = 1;
1648 IpInfo->IpVersion = IpIo->IpVersion;
1649
1650 //
1651 // Create the IP instance and open the IP protocol.
1652 //
1653 Status = IpIoCreateIpChildOpenProtocol (
1654 IpIo->Controller,
1655 IpIo->Image,
1656 &IpInfo->ChildHandle,
1657 IpInfo->IpVersion,
1658 (VOID **) &IpInfo->Ip
1659 );
1660 if (EFI_ERROR (Status)) {
1661 goto ReleaseIpInfo;
1662 }
1663
1664 //
1665 // Create the event for the DummyRcvToken.
1666 //
1667 Status = gBS->CreateEvent (
1668 EVT_NOTIFY_SIGNAL,
1669 TPL_NOTIFY,
1670 IpIoDummyHandler,
1671 IpInfo,
1672 &Event
1673 );
1674 if (EFI_ERROR (Status)) {
1675 goto ReleaseIpChild;
1676 }
1677
1678 if (IpInfo->IpVersion == IP_VERSION_4) {
1679 IpInfo->DummyRcvToken.Ip4Token.Event = Event;
1680 } else {
1681 IpInfo->DummyRcvToken.Ip6Token.Event = Event;
1682 }
1683
1684 //
1685 // Link this IpInfo into the IpIo.
1686 //
1687 InsertTailList (&IpIo->IpList, &IpInfo->Entry);
1688
1689 return IpInfo;
1690
1691 ReleaseIpChild:
1692
1693 IpIoCloseProtocolDestroyIpChild (
1694 IpIo->Controller,
1695 IpIo->Image,
1696 IpInfo->ChildHandle,
1697 IpInfo->IpVersion
1698 );
1699
1700 ReleaseIpInfo:
1701
1702 gBS->FreePool (IpInfo);
1703
1704 return NULL;
1705 }
1706
1707
1708 /**
1709 Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1710 is not NULL.
1711
1712 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1713 @param[in, out] IpConfigData The IP configure data used to configure the IP
1714 instance, if NULL the IP instance is reset. If
1715 UseDefaultAddress is set to TRUE, and the configure
1716 operation succeeds, the default address information
1717 is written back in this IpConfigData.
1718
1719 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
1720 or no need to reconfigure it.
1721 @retval Others Configuration fails.
1722
1723 **/
1724 EFI_STATUS
1725 EFIAPI
1726 IpIoConfigIp (
1727 IN OUT IP_IO_IP_INFO *IpInfo,
1728 IN OUT VOID *IpConfigData OPTIONAL
1729 )
1730 {
1731 EFI_STATUS Status;
1732 VOID *Ip;
1733 UINT8 IpVersion;
1734 EFI_IP4_MODE_DATA Ip4ModeData;
1735 EFI_IP6_MODE_DATA Ip6ModeData;
1736
1737 ASSERT (IpInfo != NULL);
1738
1739 if (IpInfo->RefCnt > 1) {
1740 //
1741 // This IP instance is shared, don't reconfigure it until it has only one
1742 // consumer. Currently, only the tcp children cloned from their passive parent
1743 // will share the same IP. So this cases only happens while IpConfigData is NULL,
1744 // let the last consumer clean the IP instance.
1745 //
1746 return EFI_SUCCESS;
1747 }
1748
1749 IpVersion = IpInfo->IpVersion;
1750 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1751
1752 Ip = IpInfo->Ip;
1753
1754 if (IpInfo->IpVersion == IP_VERSION_4) {
1755 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, IpConfigData);
1756 } else {
1757 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, IpConfigData);
1758 }
1759
1760 if (EFI_ERROR (Status)) {
1761 goto OnExit;
1762 }
1763
1764 if (IpConfigData != NULL) {
1765 if (IpInfo->IpVersion == IP_VERSION_4){
1766
1767 if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {
1768 ((EFI_IP4_PROTOCOL *) Ip)->GetModeData (
1769 (EFI_IP4_PROTOCOL *) Ip,
1770 &Ip4ModeData,
1771 NULL,
1772 NULL
1773 );
1774
1775 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress = Ip4ModeData.ConfigData.StationAddress;
1776 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask = Ip4ModeData.ConfigData.SubnetMask;
1777 }
1778
1779 CopyMem (
1780 &IpInfo->Addr.Addr,
1781 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,
1782 sizeof (IP4_ADDR)
1783 );
1784 CopyMem (
1785 &IpInfo->PreMask.SubnetMask,
1786 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,
1787 sizeof (IP4_ADDR)
1788 );
1789
1790 Status = ((EFI_IP4_PROTOCOL *) Ip)->Receive (
1791 (EFI_IP4_PROTOCOL *) Ip,
1792 &IpInfo->DummyRcvToken.Ip4Token
1793 );
1794 if (EFI_ERROR (Status)) {
1795 ((EFI_IP4_PROTOCOL*)Ip)->Configure (Ip, NULL);
1796 }
1797 } else {
1798
1799 ((EFI_IP6_PROTOCOL *) Ip)->GetModeData (
1800 (EFI_IP6_PROTOCOL *) Ip,
1801 &Ip6ModeData,
1802 NULL,
1803 NULL
1804 );
1805
1806 if (Ip6ModeData.IsConfigured) {
1807 CopyMem (
1808 &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,
1809 &Ip6ModeData.ConfigData.StationAddress,
1810 sizeof (EFI_IPv6_ADDRESS)
1811 );
1812
1813 if (Ip6ModeData.AddressList != NULL) {
1814 FreePool (Ip6ModeData.AddressList);
1815 }
1816
1817 if (Ip6ModeData.GroupTable != NULL) {
1818 FreePool (Ip6ModeData.GroupTable);
1819 }
1820
1821 if (Ip6ModeData.RouteTable != NULL) {
1822 FreePool (Ip6ModeData.RouteTable);
1823 }
1824
1825 if (Ip6ModeData.NeighborCache != NULL) {
1826 FreePool (Ip6ModeData.NeighborCache);
1827 }
1828
1829 if (Ip6ModeData.PrefixTable != NULL) {
1830 FreePool (Ip6ModeData.PrefixTable);
1831 }
1832
1833 if (Ip6ModeData.IcmpTypeList != NULL) {
1834 FreePool (Ip6ModeData.IcmpTypeList);
1835 }
1836
1837 } else {
1838 Status = EFI_NO_MAPPING;
1839 goto OnExit;
1840 }
1841
1842 CopyMem (
1843 &IpInfo->Addr,
1844 &Ip6ModeData.ConfigData.StationAddress,
1845 sizeof (EFI_IPv6_ADDRESS)
1846 );
1847
1848 Status = ((EFI_IP6_PROTOCOL *) Ip)->Receive (
1849 (EFI_IP6_PROTOCOL *) Ip,
1850 &IpInfo->DummyRcvToken.Ip6Token
1851 );
1852 if (EFI_ERROR (Status)) {
1853 ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);
1854 }
1855 }
1856 } else {
1857 //
1858 // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1859 //
1860 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1861 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1862 }
1863
1864 OnExit:
1865
1866 return Status;
1867 }
1868
1869
1870 /**
1871 Destroy an IP instance maintained in IpIo->IpList for
1872 sending purpose.
1873
1874 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1875 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1876 will be dstroyed if the RefCnt is zero.
1877
1878 @param[in] IpIo Pointer to the IP_IO instance.
1879 @param[in] IpInfo Pointer to the IpInfo to be removed.
1880
1881 **/
1882 VOID
1883 EFIAPI
1884 IpIoRemoveIp (
1885 IN IP_IO *IpIo,
1886 IN IP_IO_IP_INFO *IpInfo
1887 )
1888 {
1889
1890 UINT8 IpVersion;
1891
1892 ASSERT (IpInfo->RefCnt > 0);
1893
1894 NET_PUT_REF (IpInfo);
1895
1896 if (IpInfo->RefCnt > 0) {
1897
1898 return;
1899 }
1900
1901 IpVersion = IpIo->IpVersion;
1902
1903 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1904
1905 RemoveEntryList (&IpInfo->Entry);
1906
1907 if (IpVersion == IP_VERSION_4){
1908 ((EFI_IP4_PROTOCOL *) (IpInfo->Ip))->Configure (
1909 (EFI_IP4_PROTOCOL *) (IpInfo->Ip),
1910 NULL
1911 );
1912 IpIoCloseProtocolDestroyIpChild (
1913 IpIo->Controller,
1914 IpIo->Image,
1915 IpInfo->ChildHandle,
1916 IP_VERSION_4
1917 );
1918
1919 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);
1920
1921 } else {
1922
1923 ((EFI_IP6_PROTOCOL *) (IpInfo->Ip))->Configure (
1924 (EFI_IP6_PROTOCOL *) (IpInfo->Ip),
1925 NULL
1926 );
1927
1928 IpIoCloseProtocolDestroyIpChild (
1929 IpIo->Controller,
1930 IpIo->Image,
1931 IpInfo->ChildHandle,
1932 IP_VERSION_6
1933 );
1934
1935 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);
1936 }
1937
1938 FreePool (IpInfo);
1939 }
1940
1941
1942 /**
1943 Find the first IP protocol maintained in IpIo whose local
1944 address is the same as Src.
1945
1946 This function is called when the caller needs the IpIo to send data to the
1947 specified Src. The IpIo was added previously by IpIoAddIp().
1948
1949 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
1950 @param[in] IpVersion The version of the IP protocol to use, either
1951 IPv4 or IPv6.
1952 @param[in] Src The local IP address.
1953
1954 @return Pointer to the IP protocol can be used for sending purpose and its local
1955 address is the same with Src.
1956
1957 **/
1958 IP_IO_IP_INFO *
1959 EFIAPI
1960 IpIoFindSender (
1961 IN OUT IP_IO **IpIo,
1962 IN UINT8 IpVersion,
1963 IN EFI_IP_ADDRESS *Src
1964 )
1965 {
1966 LIST_ENTRY *IpIoEntry;
1967 IP_IO *IpIoPtr;
1968 LIST_ENTRY *IpInfoEntry;
1969 IP_IO_IP_INFO *IpInfo;
1970
1971 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1972
1973 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
1974 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
1975
1976 if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {
1977 continue;
1978 }
1979
1980 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
1981 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
1982 if (IpInfo->IpVersion == IP_VERSION_4){
1983
1984 if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {
1985 *IpIo = IpIoPtr;
1986 return IpInfo;
1987 }
1988
1989 } else {
1990
1991 if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {
1992 *IpIo = IpIoPtr;
1993 return IpInfo;
1994 }
1995 }
1996
1997 }
1998 }
1999
2000 //
2001 // No match.
2002 //
2003 return NULL;
2004 }
2005
2006
2007 /**
2008 Get the ICMP error map information.
2009
2010 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2011 are not NULL, this routine will fill them.
2012
2013 @param[in] IcmpError IcmpError Type.
2014 @param[in] IpVersion The version of the IP protocol to use,
2015 either IPv4 or IPv6.
2016
2017 @param[out] IsHard Whether it is a hard error.
2018 @param[out] Notify Whether it need to notify SockError.
2019
2020 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2021
2022 **/
2023 EFI_STATUS
2024 EFIAPI
2025 IpIoGetIcmpErrStatus (
2026 IN UINT8 IcmpError,
2027 IN UINT8 IpVersion,
2028 OUT BOOLEAN *IsHard OPTIONAL,
2029 OUT BOOLEAN *Notify OPTIONAL
2030 )
2031 {
2032 if (IpVersion == IP_VERSION_4 ) {
2033 ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);
2034
2035 if (IsHard != NULL) {
2036 *IsHard = mIcmpErrMap[IcmpError].IsHard;
2037 }
2038
2039 if (Notify != NULL) {
2040 *Notify = mIcmpErrMap[IcmpError].Notify;
2041 }
2042
2043 switch (IcmpError) {
2044 case ICMP_ERR_UNREACH_NET:
2045 return EFI_NETWORK_UNREACHABLE;
2046
2047 case ICMP_ERR_TIMXCEED_INTRANS:
2048 case ICMP_ERR_TIMXCEED_REASS:
2049 case ICMP_ERR_UNREACH_HOST:
2050 return EFI_HOST_UNREACHABLE;
2051
2052 case ICMP_ERR_UNREACH_PROTOCOL:
2053 return EFI_PROTOCOL_UNREACHABLE;
2054
2055 case ICMP_ERR_UNREACH_PORT:
2056 return EFI_PORT_UNREACHABLE;
2057
2058 case ICMP_ERR_MSGSIZE:
2059 case ICMP_ERR_UNREACH_SRCFAIL:
2060 case ICMP_ERR_QUENCH:
2061 case ICMP_ERR_PARAMPROB:
2062 return EFI_ICMP_ERROR;
2063
2064 default:
2065 ASSERT (FALSE);
2066 return EFI_UNSUPPORTED;
2067 }
2068
2069 } else if (IpVersion == IP_VERSION_6) {
2070
2071 ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);
2072
2073 if (IsHard != NULL) {
2074 *IsHard = mIcmp6ErrMap[IcmpError].IsHard;
2075 }
2076
2077 if (Notify != NULL) {
2078 *Notify = mIcmp6ErrMap[IcmpError].Notify;
2079 }
2080
2081 switch (IcmpError) {
2082 case ICMP6_ERR_UNREACH_NET:
2083 return EFI_NETWORK_UNREACHABLE;
2084
2085 case ICMP6_ERR_UNREACH_HOST:
2086 case ICMP6_ERR_TIMXCEED_HOPLIMIT:
2087 case ICMP6_ERR_TIMXCEED_REASS:
2088 return EFI_HOST_UNREACHABLE;
2089
2090 case ICMP6_ERR_UNREACH_PROTOCOL:
2091 return EFI_PROTOCOL_UNREACHABLE;
2092
2093 case ICMP6_ERR_UNREACH_PORT:
2094 return EFI_PORT_UNREACHABLE;
2095
2096 case ICMP6_ERR_PACKAGE_TOOBIG:
2097 case ICMP6_ERR_PARAMPROB_HEADER:
2098 case ICMP6_ERR_PARAMPROB_NEXHEADER:
2099 case ICMP6_ERR_PARAMPROB_IPV6OPTION:
2100 return EFI_ICMP_ERROR;
2101
2102 default:
2103 ASSERT (FALSE);
2104 return EFI_UNSUPPORTED;
2105 }
2106
2107 } else {
2108 //
2109 // Should never be here
2110 //
2111 ASSERT (FALSE);
2112 return EFI_UNSUPPORTED;
2113 }
2114 }
2115
2116
2117 /**
2118 Refresh the remote peer's Neighbor Cache entries.
2119
2120 This function is called when the caller needs the IpIo to refresh the existing
2121 IPv6 neighbor cache entries since the neighbor is considered reachable by the
2122 node has recently received a confirmation that packets sent recently to the
2123 neighbor were received by its IP layer.
2124
2125 @param[in] IpIo Pointer to an IP_IO instance
2126 @param[in] Neighbor The IP address of the neighbor
2127 @param[in] Timeout Time in 100-ns units that this entry will
2128 remain in the neighbor cache. A value of
2129 zero means that the entry is permanent.
2130 A value of non-zero means that the entry is
2131 dynamic and will be deleted after Timeout.
2132
2133 @retval EFI_SUCCESS The operation is completed successfully.
2134 @retval EFI_NOT_STARTED The IpIo is not configured.
2135 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
2136 @retval EFI_NOT_FOUND The neighbor cache entry is not in the
2137 neighbor table.
2138 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
2139
2140 **/
2141 EFI_STATUS
2142 IpIoRefreshNeighbor (
2143 IN IP_IO *IpIo,
2144 IN EFI_IP_ADDRESS *Neighbor,
2145 IN UINT32 Timeout
2146 )
2147 {
2148 EFI_IP6_PROTOCOL *Ip;
2149
2150 if (!IpIo->IsConfigured || IpIo->IpVersion != IP_VERSION_6) {
2151 return EFI_NOT_STARTED;
2152 }
2153
2154 Ip = (EFI_IP6_PROTOCOL *) (IpIo->Ip);
2155
2156 return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);
2157 }
2158