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