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