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