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