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