]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
MdeModulePkg: Clean up source files
[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 - 2018, 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 any error occurs,
638 then return NULL.
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)) {
1043 //
1044 // Only process the normal packets and the icmp error packets.
1045 //
1046 if (RxData != NULL) {
1047 goto CleanUp;
1048 } else {
1049 goto Resume;
1050 }
1051 }
1052
1053 //
1054 // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).
1055 //
1056 ASSERT (RxData != NULL);
1057 if (RxData == NULL) {
1058 goto Resume;
1059 }
1060
1061 if (NULL == IpIo->PktRcvdNotify) {
1062 goto CleanUp;
1063 }
1064
1065 if (IpIo->IpVersion == IP_VERSION_4) {
1066 ASSERT (RxData->Ip4RxData.Header != NULL);
1067 if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress))) {
1068 //
1069 // The source address is a broadcast address, discard it.
1070 //
1071 goto CleanUp;
1072 }
1073 if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&
1074 (IpIo->SubnetMask != 0) &&
1075 IP4_NET_EQUAL (IpIo->StationIp, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask) &&
1076 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask)) {
1077 //
1078 // The source address doesn't match StationIp and it's not a unicast IP address, discard it.
1079 //
1080 goto CleanUp;
1081 }
1082
1083 if (RxData->Ip4RxData.DataLength == 0) {
1084 //
1085 // Discard zero length data payload packet.
1086 //
1087 goto CleanUp;
1088 }
1089
1090 //
1091 // The fragment should always be valid for non-zero length packet.
1092 //
1093 ASSERT (RxData->Ip4RxData.FragmentCount != 0);
1094
1095 //
1096 // Create a netbuffer representing IPv4 packet
1097 //
1098 Pkt = NetbufFromExt (
1099 (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,
1100 RxData->Ip4RxData.FragmentCount,
1101 0,
1102 0,
1103 IpIoExtFree,
1104 RxData->Ip4RxData.RecycleSignal
1105 );
1106 if (NULL == Pkt) {
1107 goto CleanUp;
1108 }
1109
1110 //
1111 // Create a net session
1112 //
1113 Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);
1114 Session.Dest.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);
1115 Session.IpHdr.Ip4Hdr = RxData->Ip4RxData.Header;
1116 Session.IpHdrLen = RxData->Ip4RxData.HeaderLength;
1117 Session.IpVersion = IP_VERSION_4;
1118 } else {
1119 ASSERT (RxData->Ip6RxData.Header != NULL);
1120 if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {
1121 goto CleanUp;
1122 }
1123
1124 if (RxData->Ip6RxData.DataLength == 0) {
1125 //
1126 // Discard zero length data payload packet.
1127 //
1128 goto CleanUp;
1129 }
1130
1131 //
1132 // The fragment should always be valid for non-zero length packet.
1133 //
1134 ASSERT (RxData->Ip6RxData.FragmentCount != 0);
1135
1136 //
1137 // Create a netbuffer representing IPv6 packet
1138 //
1139 Pkt = NetbufFromExt (
1140 (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,
1141 RxData->Ip6RxData.FragmentCount,
1142 0,
1143 0,
1144 IpIoExtFree,
1145 RxData->Ip6RxData.RecycleSignal
1146 );
1147 if (NULL == Pkt) {
1148 goto CleanUp;
1149 }
1150
1151 //
1152 // Create a net session
1153 //
1154 CopyMem (
1155 &Session.Source,
1156 &RxData->Ip6RxData.Header->SourceAddress,
1157 sizeof(EFI_IPv6_ADDRESS)
1158 );
1159 CopyMem (
1160 &Session.Dest,
1161 &RxData->Ip6RxData.Header->DestinationAddress,
1162 sizeof(EFI_IPv6_ADDRESS)
1163 );
1164 Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;
1165 Session.IpHdrLen = RxData->Ip6RxData.HeaderLength;
1166 Session.IpVersion = IP_VERSION_6;
1167 }
1168
1169 if (EFI_SUCCESS == Status) {
1170
1171 IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);
1172 } else {
1173 //
1174 // Status is EFI_ICMP_ERROR
1175 //
1176 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
1177 if (EFI_ERROR (Status)) {
1178 NetbufFree (Pkt);
1179 }
1180 }
1181
1182 goto Resume;
1183
1184 CleanUp:
1185
1186 if (IpIo->IpVersion == IP_VERSION_4){
1187 gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);
1188 } else {
1189 gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);
1190 }
1191
1192 Resume:
1193
1194 if (IpIo->IpVersion == IP_VERSION_4){
1195 IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));
1196 } else {
1197 IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));
1198 }
1199 }
1200
1201 /**
1202 This function add IpIoListenHandlerDpc to the end of the DPC queue.
1203
1204 @param[in] Event The event signaled.
1205 @param[in] Context The context passed in by the event notifier.
1206
1207 **/
1208 VOID
1209 EFIAPI
1210 IpIoListenHandler (
1211 IN EFI_EVENT Event,
1212 IN VOID *Context
1213 )
1214 {
1215 //
1216 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1217 //
1218 QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
1219 }
1220
1221
1222 /**
1223 Create a new IP_IO instance.
1224
1225 If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1226
1227 This function uses IP4/IP6 service binding protocol in Controller to create
1228 an IP4/IP6 child (aka IP4/IP6 instance).
1229
1230 @param[in] Image The image handle of the driver or application that
1231 consumes IP_IO.
1232 @param[in] Controller The controller handle that has IP4 or IP6 service
1233 binding protocol installed.
1234 @param[in] IpVersion The version of the IP protocol to use, either
1235 IPv4 or IPv6.
1236
1237 @return Pointer to a newly created IP_IO instance, or NULL if failed.
1238
1239 **/
1240 IP_IO *
1241 EFIAPI
1242 IpIoCreate (
1243 IN EFI_HANDLE Image,
1244 IN EFI_HANDLE Controller,
1245 IN UINT8 IpVersion
1246 )
1247 {
1248 EFI_STATUS Status;
1249 IP_IO *IpIo;
1250 EFI_EVENT Event;
1251
1252 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1253
1254 IpIo = AllocateZeroPool (sizeof (IP_IO));
1255 if (NULL == IpIo) {
1256 return NULL;
1257 }
1258
1259 InitializeListHead (&(IpIo->PendingSndList));
1260 InitializeListHead (&(IpIo->IpList));
1261 IpIo->Controller = Controller;
1262 IpIo->Image = Image;
1263 IpIo->IpVersion = IpVersion;
1264 Event = NULL;
1265
1266 Status = gBS->CreateEvent (
1267 EVT_NOTIFY_SIGNAL,
1268 TPL_NOTIFY,
1269 IpIoListenHandler,
1270 IpIo,
1271 &Event
1272 );
1273 if (EFI_ERROR (Status)) {
1274 goto ReleaseIpIo;
1275 }
1276
1277 if (IpVersion == IP_VERSION_4) {
1278 IpIo->RcvToken.Ip4Token.Event = Event;
1279 } else {
1280 IpIo->RcvToken.Ip6Token.Event = Event;
1281 }
1282
1283 //
1284 // Create an IP child and open IP protocol
1285 //
1286 Status = IpIoCreateIpChildOpenProtocol (
1287 Controller,
1288 Image,
1289 &IpIo->ChildHandle,
1290 IpVersion,
1291 (VOID **) & (IpIo->Ip)
1292 );
1293 if (EFI_ERROR (Status)) {
1294 goto ReleaseIpIo;
1295 }
1296
1297 return IpIo;
1298
1299 ReleaseIpIo:
1300
1301 if (Event != NULL) {
1302 gBS->CloseEvent (Event);
1303 }
1304
1305 gBS->FreePool (IpIo);
1306
1307 return NULL;
1308 }
1309
1310
1311 /**
1312 Open an IP_IO instance for use.
1313
1314 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1315
1316 This function is called after IpIoCreate(). It is used for configuring the IP
1317 instance and register the callbacks and their context data for sending and
1318 receiving IP packets.
1319
1320 @param[in, out] IpIo Pointer to an IP_IO instance that needs
1321 to open.
1322 @param[in] OpenData The configuration data and callbacks for
1323 the IP_IO instance.
1324
1325 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
1326 successfully.
1327 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
1328 reopen it.
1329 @retval EFI_UNSUPPORTED IPv4 RawData mode is no supported.
1330 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1331 @retval Others Error condition occurred.
1332
1333 **/
1334 EFI_STATUS
1335 EFIAPI
1336 IpIoOpen (
1337 IN OUT IP_IO *IpIo,
1338 IN IP_IO_OPEN_DATA *OpenData
1339 )
1340 {
1341 EFI_STATUS Status;
1342 UINT8 IpVersion;
1343
1344 if (IpIo == NULL || OpenData == NULL) {
1345 return EFI_INVALID_PARAMETER;
1346 }
1347
1348 if (IpIo->IsConfigured) {
1349 return EFI_ACCESS_DENIED;
1350 }
1351
1352 IpVersion = IpIo->IpVersion;
1353
1354 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1355
1356 //
1357 // configure ip
1358 //
1359 if (IpVersion == IP_VERSION_4){
1360 //
1361 // RawData mode is no supported.
1362 //
1363 ASSERT (!OpenData->IpConfigData.Ip4CfgData.RawData);
1364 if (OpenData->IpConfigData.Ip4CfgData.RawData) {
1365 return EFI_UNSUPPORTED;
1366 }
1367
1368 if (!OpenData->IpConfigData.Ip4CfgData.UseDefaultAddress) {
1369 IpIo->StationIp = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.StationAddress);
1370 IpIo->SubnetMask = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.SubnetMask);
1371 }
1372
1373 Status = IpIo->Ip.Ip4->Configure (
1374 IpIo->Ip.Ip4,
1375 &OpenData->IpConfigData.Ip4CfgData
1376 );
1377 } else {
1378
1379 Status = IpIo->Ip.Ip6->Configure (
1380 IpIo->Ip.Ip6,
1381 &OpenData->IpConfigData.Ip6CfgData
1382 );
1383 }
1384
1385 if (EFI_ERROR (Status)) {
1386 return Status;
1387 }
1388
1389 //
1390 // @bug To delete the default route entry in this Ip, if it is:
1391 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1392 // @bug its code
1393 //
1394 if (IpVersion == IP_VERSION_4){
1395 Status = IpIo->Ip.Ip4->Routes (
1396 IpIo->Ip.Ip4,
1397 TRUE,
1398 &mZeroIp4Addr,
1399 &mZeroIp4Addr,
1400 &mZeroIp4Addr
1401 );
1402
1403 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
1404 return Status;
1405 }
1406 }
1407
1408 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
1409 IpIo->PktSentNotify = OpenData->PktSentNotify;
1410
1411 IpIo->RcvdContext = OpenData->RcvdContext;
1412 IpIo->SndContext = OpenData->SndContext;
1413
1414 if (IpVersion == IP_VERSION_4){
1415 IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;
1416
1417 //
1418 // start to listen incoming packet
1419 //
1420 Status = IpIo->Ip.Ip4->Receive (
1421 IpIo->Ip.Ip4,
1422 &(IpIo->RcvToken.Ip4Token)
1423 );
1424 if (EFI_ERROR (Status)) {
1425 IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
1426 return Status;
1427 }
1428
1429 } else {
1430
1431 IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;
1432 Status = IpIo->Ip.Ip6->Receive (
1433 IpIo->Ip.Ip6,
1434 &(IpIo->RcvToken.Ip6Token)
1435 );
1436 if (EFI_ERROR (Status)) {
1437 IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
1438 return Status;
1439 }
1440 }
1441
1442 IpIo->IsConfigured = TRUE;
1443 InsertTailList (&mActiveIpIoList, &IpIo->Entry);
1444
1445 return Status;
1446 }
1447
1448
1449 /**
1450 Stop an IP_IO instance.
1451
1452 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1453
1454 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1455 the pending send/receive tokens will be canceled.
1456
1457 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
1458
1459 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
1460 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1461 @retval Others Error condition occurred.
1462
1463 **/
1464 EFI_STATUS
1465 EFIAPI
1466 IpIoStop (
1467 IN OUT IP_IO *IpIo
1468 )
1469 {
1470 EFI_STATUS Status;
1471 IP_IO_IP_INFO *IpInfo;
1472 UINT8 IpVersion;
1473
1474 if (IpIo == NULL) {
1475 return EFI_INVALID_PARAMETER;
1476 }
1477
1478 if (!IpIo->IsConfigured) {
1479 return EFI_SUCCESS;
1480 }
1481
1482 IpVersion = IpIo->IpVersion;
1483
1484 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1485
1486 //
1487 // Remove the IpIo from the active IpIo list.
1488 //
1489 RemoveEntryList (&IpIo->Entry);
1490
1491 //
1492 // Configure NULL Ip
1493 //
1494 if (IpVersion == IP_VERSION_4) {
1495 Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
1496 } else {
1497 Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
1498 }
1499 if (EFI_ERROR (Status)) {
1500 return Status;
1501 }
1502
1503 IpIo->IsConfigured = FALSE;
1504
1505 //
1506 // Detroy the Ip List used by IpIo
1507 //
1508
1509 while (!IsListEmpty (&(IpIo->IpList))) {
1510 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
1511
1512 IpIoRemoveIp (IpIo, IpInfo);
1513 }
1514
1515 //
1516 // All pending send tokens should be flushed by resetting the IP instances.
1517 //
1518 ASSERT (IsListEmpty (&IpIo->PendingSndList));
1519
1520 //
1521 // Close the receive event.
1522 //
1523 if (IpVersion == IP_VERSION_4){
1524 gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);
1525 } else {
1526 gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);
1527 }
1528
1529 return EFI_SUCCESS;
1530 }
1531
1532
1533 /**
1534 Destroy an IP_IO instance.
1535
1536 This function is paired with IpIoCreate(). The IP_IO will be closed first.
1537 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1538
1539 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
1540 destroyed.
1541
1542 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
1543 @retval Others Error condition occurred.
1544
1545 **/
1546 EFI_STATUS
1547 EFIAPI
1548 IpIoDestroy (
1549 IN OUT IP_IO *IpIo
1550 )
1551 {
1552 EFI_STATUS Status;
1553
1554 //
1555 // Stop the IpIo.
1556 //
1557 Status = IpIoStop (IpIo);
1558 if (EFI_ERROR (Status)) {
1559 return Status;
1560 }
1561
1562 //
1563 // Close the IP protocol and destroy the child.
1564 //
1565 Status = IpIoCloseProtocolDestroyIpChild (
1566 IpIo->Controller,
1567 IpIo->Image,
1568 IpIo->ChildHandle,
1569 IpIo->IpVersion
1570 );
1571 if (EFI_ERROR (Status)) {
1572 return Status;
1573 }
1574
1575 gBS->FreePool (IpIo);
1576
1577 return EFI_SUCCESS;
1578 }
1579
1580
1581 /**
1582 Send out an IP packet.
1583
1584 This function is called after IpIoOpen(). The data to be sent is wrapped in
1585 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1586 overriden by Sender. Other sending configs, like source address and gateway
1587 address etc., are specified in OverrideData.
1588
1589 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1590 packet.
1591 @param[in, out] Pkt Pointer to the IP packet to be sent.
1592 @param[in] Sender The IP protocol instance used for sending.
1593 @param[in] Context Optional context data.
1594 @param[in] NotifyData Optional notify data.
1595 @param[in] Dest The destination IP address to send this packet to.
1596 This parameter is optional when using IPv6.
1597 @param[in] OverrideData The data to override some configuration of the IP
1598 instance used for sending.
1599
1600 @retval EFI_SUCCESS The operation is completed successfully.
1601 @retval EFI_INVALID_PARAMETER The input parameter is not correct.
1602 @retval EFI_NOT_STARTED The IpIo is not configured.
1603 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1604 @retval Others Error condition occurred.
1605
1606 **/
1607 EFI_STATUS
1608 EFIAPI
1609 IpIoSend (
1610 IN OUT IP_IO *IpIo,
1611 IN OUT NET_BUF *Pkt,
1612 IN IP_IO_IP_INFO *Sender OPTIONAL,
1613 IN VOID *Context OPTIONAL,
1614 IN VOID *NotifyData OPTIONAL,
1615 IN EFI_IP_ADDRESS *Dest OPTIONAL,
1616 IN IP_IO_OVERRIDE *OverrideData OPTIONAL
1617 )
1618 {
1619 EFI_STATUS Status;
1620 IP_IO_IP_PROTOCOL Ip;
1621 IP_IO_SEND_ENTRY *SndEntry;
1622
1623 if ((IpIo == NULL) || (Pkt == NULL)) {
1624 return EFI_INVALID_PARAMETER;
1625 }
1626
1627 if ((IpIo->IpVersion == IP_VERSION_4) && (Dest == NULL)) {
1628 return EFI_INVALID_PARAMETER;
1629 }
1630
1631 if (!IpIo->IsConfigured) {
1632 return EFI_NOT_STARTED;
1633 }
1634
1635 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
1636
1637 //
1638 // create a new SndEntry
1639 //
1640 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
1641 if (NULL == SndEntry) {
1642 return EFI_OUT_OF_RESOURCES;
1643 }
1644
1645 //
1646 // Send this Packet
1647 //
1648 if (IpIo->IpVersion == IP_VERSION_4){
1649 Status = Ip.Ip4->Transmit (
1650 Ip.Ip4,
1651 &SndEntry->SndToken.Ip4Token
1652 );
1653 } else {
1654 Status = Ip.Ip6->Transmit (
1655 Ip.Ip6,
1656 &SndEntry->SndToken.Ip6Token
1657 );
1658 }
1659
1660 if (EFI_ERROR (Status)) {
1661 IpIoDestroySndEntry (SndEntry);
1662 }
1663
1664 return Status;
1665 }
1666
1667
1668 /**
1669 Cancel the IP transmit token which wraps this Packet.
1670
1671 If IpIo is NULL, then ASSERT().
1672 If Packet is NULL, then ASSERT().
1673
1674 @param[in] IpIo Pointer to the IP_IO instance.
1675 @param[in] Packet Pointer to the packet of NET_BUF to cancel.
1676
1677 **/
1678 VOID
1679 EFIAPI
1680 IpIoCancelTxToken (
1681 IN IP_IO *IpIo,
1682 IN VOID *Packet
1683 )
1684 {
1685 LIST_ENTRY *Node;
1686 IP_IO_SEND_ENTRY *SndEntry;
1687 IP_IO_IP_PROTOCOL Ip;
1688
1689 ASSERT ((IpIo != NULL) && (Packet != NULL));
1690
1691 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
1692
1693 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
1694
1695 if (SndEntry->Pkt == Packet) {
1696
1697 Ip = SndEntry->Ip;
1698
1699 if (IpIo->IpVersion == IP_VERSION_4) {
1700 Ip.Ip4->Cancel (
1701 Ip.Ip4,
1702 &SndEntry->SndToken.Ip4Token
1703 );
1704 } else {
1705 Ip.Ip6->Cancel (
1706 Ip.Ip6,
1707 &SndEntry->SndToken.Ip6Token
1708 );
1709 }
1710
1711 break;
1712 }
1713 }
1714
1715 }
1716
1717
1718 /**
1719 Add a new IP instance for sending data.
1720
1721 If IpIo is NULL, then ASSERT().
1722 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1723
1724 The function is used to add the IP_IO to the IP_IO sending list. The caller
1725 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1726 data.
1727
1728 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
1729 instance for sending purpose.
1730
1731 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1732
1733 **/
1734 IP_IO_IP_INFO *
1735 EFIAPI
1736 IpIoAddIp (
1737 IN OUT IP_IO *IpIo
1738 )
1739 {
1740 EFI_STATUS Status;
1741 IP_IO_IP_INFO *IpInfo;
1742 EFI_EVENT Event;
1743
1744 ASSERT (IpIo != NULL);
1745 ASSERT ((IpIo->IpVersion == IP_VERSION_4) || (IpIo->IpVersion == IP_VERSION_6));
1746
1747 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
1748 if (IpInfo == NULL) {
1749 return NULL;
1750 }
1751
1752 //
1753 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1754 // instance.
1755 //
1756 InitializeListHead (&IpInfo->Entry);
1757 IpInfo->ChildHandle = NULL;
1758 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1759 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1760
1761 IpInfo->RefCnt = 1;
1762 IpInfo->IpVersion = IpIo->IpVersion;
1763
1764 //
1765 // Create the IP instance and open the IP protocol.
1766 //
1767 Status = IpIoCreateIpChildOpenProtocol (
1768 IpIo->Controller,
1769 IpIo->Image,
1770 &IpInfo->ChildHandle,
1771 IpInfo->IpVersion,
1772 (VOID **) &IpInfo->Ip
1773 );
1774 if (EFI_ERROR (Status)) {
1775 goto ReleaseIpInfo;
1776 }
1777
1778 //
1779 // Create the event for the DummyRcvToken.
1780 //
1781 Status = gBS->CreateEvent (
1782 EVT_NOTIFY_SIGNAL,
1783 TPL_NOTIFY,
1784 IpIoDummyHandler,
1785 IpInfo,
1786 &Event
1787 );
1788 if (EFI_ERROR (Status)) {
1789 goto ReleaseIpChild;
1790 }
1791
1792 if (IpInfo->IpVersion == IP_VERSION_4) {
1793 IpInfo->DummyRcvToken.Ip4Token.Event = Event;
1794 } else {
1795 IpInfo->DummyRcvToken.Ip6Token.Event = Event;
1796 }
1797
1798 //
1799 // Link this IpInfo into the IpIo.
1800 //
1801 InsertTailList (&IpIo->IpList, &IpInfo->Entry);
1802
1803 return IpInfo;
1804
1805 ReleaseIpChild:
1806
1807 IpIoCloseProtocolDestroyIpChild (
1808 IpIo->Controller,
1809 IpIo->Image,
1810 IpInfo->ChildHandle,
1811 IpInfo->IpVersion
1812 );
1813
1814 ReleaseIpInfo:
1815
1816 gBS->FreePool (IpInfo);
1817
1818 return NULL;
1819 }
1820
1821
1822 /**
1823 Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1824 is not NULL.
1825
1826 If IpInfo is NULL, then ASSERT().
1827 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1828
1829 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1830 @param[in, out] IpConfigData The IP configure data used to configure the IP
1831 instance, if NULL the IP instance is reset. If
1832 UseDefaultAddress is set to TRUE, and the configure
1833 operation succeeds, the default address information
1834 is written back in this IpConfigData.
1835
1836 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
1837 or no need to reconfigure it.
1838 @retval Others Configuration fails.
1839
1840 **/
1841 EFI_STATUS
1842 EFIAPI
1843 IpIoConfigIp (
1844 IN OUT IP_IO_IP_INFO *IpInfo,
1845 IN OUT VOID *IpConfigData OPTIONAL
1846 )
1847 {
1848 EFI_STATUS Status;
1849 IP_IO_IP_PROTOCOL Ip;
1850 UINT8 IpVersion;
1851 EFI_IP4_MODE_DATA Ip4ModeData;
1852 EFI_IP6_MODE_DATA Ip6ModeData;
1853
1854 ASSERT (IpInfo != NULL);
1855
1856 if (IpInfo->RefCnt > 1) {
1857 //
1858 // This IP instance is shared, don't reconfigure it until it has only one
1859 // consumer. Currently, only the tcp children cloned from their passive parent
1860 // will share the same IP. So this cases only happens while IpConfigData is NULL,
1861 // let the last consumer clean the IP instance.
1862 //
1863 return EFI_SUCCESS;
1864 }
1865
1866 IpVersion = IpInfo->IpVersion;
1867 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
1868
1869 Ip = IpInfo->Ip;
1870
1871 if (IpInfo->IpVersion == IP_VERSION_4) {
1872 Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);
1873 } else {
1874 Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);
1875 }
1876
1877 if (EFI_ERROR (Status)) {
1878 return Status;
1879 }
1880
1881 if (IpConfigData != NULL) {
1882 if (IpInfo->IpVersion == IP_VERSION_4) {
1883
1884 if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {
1885 Status = Ip.Ip4->GetModeData (
1886 Ip.Ip4,
1887 &Ip4ModeData,
1888 NULL,
1889 NULL
1890 );
1891 if (EFI_ERROR (Status)) {
1892 Ip.Ip4->Configure (Ip.Ip4, NULL);
1893 return Status;
1894 }
1895
1896 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);
1897 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);
1898 }
1899
1900 CopyMem (
1901 &IpInfo->Addr.Addr,
1902 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,
1903 sizeof (IP4_ADDR)
1904 );
1905 CopyMem (
1906 &IpInfo->PreMask.SubnetMask,
1907 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,
1908 sizeof (IP4_ADDR)
1909 );
1910
1911 Status = Ip.Ip4->Receive (
1912 Ip.Ip4,
1913 &IpInfo->DummyRcvToken.Ip4Token
1914 );
1915 if (EFI_ERROR (Status)) {
1916 Ip.Ip4->Configure (Ip.Ip4, NULL);
1917 }
1918 } else {
1919 Status = Ip.Ip6->GetModeData (
1920 Ip.Ip6,
1921 &Ip6ModeData,
1922 NULL,
1923 NULL
1924 );
1925 if (EFI_ERROR (Status)) {
1926 Ip.Ip6->Configure (Ip.Ip6, NULL);
1927 return Status;
1928 }
1929
1930 if (Ip6ModeData.IsConfigured) {
1931 CopyMem (
1932 &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,
1933 &Ip6ModeData.ConfigData.StationAddress,
1934 sizeof (EFI_IPv6_ADDRESS)
1935 );
1936
1937 if (Ip6ModeData.AddressList != NULL) {
1938 FreePool (Ip6ModeData.AddressList);
1939 }
1940
1941 if (Ip6ModeData.GroupTable != NULL) {
1942 FreePool (Ip6ModeData.GroupTable);
1943 }
1944
1945 if (Ip6ModeData.RouteTable != NULL) {
1946 FreePool (Ip6ModeData.RouteTable);
1947 }
1948
1949 if (Ip6ModeData.NeighborCache != NULL) {
1950 FreePool (Ip6ModeData.NeighborCache);
1951 }
1952
1953 if (Ip6ModeData.PrefixTable != NULL) {
1954 FreePool (Ip6ModeData.PrefixTable);
1955 }
1956
1957 if (Ip6ModeData.IcmpTypeList != NULL) {
1958 FreePool (Ip6ModeData.IcmpTypeList);
1959 }
1960
1961 } else {
1962 Status = EFI_NO_MAPPING;
1963 return Status;
1964 }
1965
1966 CopyMem (
1967 &IpInfo->Addr,
1968 &Ip6ModeData.ConfigData.StationAddress,
1969 sizeof (EFI_IPv6_ADDRESS)
1970 );
1971
1972 Status = Ip.Ip6->Receive (
1973 Ip.Ip6,
1974 &IpInfo->DummyRcvToken.Ip6Token
1975 );
1976 if (EFI_ERROR (Status)) {
1977 Ip.Ip6->Configure (Ip.Ip6, NULL);
1978 }
1979 }
1980 } else {
1981 //
1982 // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1983 //
1984 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
1985 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
1986 }
1987
1988 return Status;
1989 }
1990
1991
1992 /**
1993 Destroy an IP instance maintained in IpIo->IpList for
1994 sending purpose.
1995
1996 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1997
1998 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1999 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
2000 will be dstroyed if the RefCnt is zero.
2001
2002 @param[in] IpIo Pointer to the IP_IO instance.
2003 @param[in] IpInfo Pointer to the IpInfo to be removed.
2004
2005 **/
2006 VOID
2007 EFIAPI
2008 IpIoRemoveIp (
2009 IN IP_IO *IpIo,
2010 IN IP_IO_IP_INFO *IpInfo
2011 )
2012 {
2013
2014 UINT8 IpVersion;
2015
2016 if (IpIo == NULL || IpInfo == NULL) {
2017 return;
2018 }
2019
2020 ASSERT (IpInfo->RefCnt > 0);
2021
2022 NET_PUT_REF (IpInfo);
2023
2024 if (IpInfo->RefCnt > 0) {
2025
2026 return;
2027 }
2028
2029 IpVersion = IpIo->IpVersion;
2030
2031 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
2032
2033 RemoveEntryList (&IpInfo->Entry);
2034
2035 if (IpVersion == IP_VERSION_4){
2036 IpInfo->Ip.Ip4->Configure (
2037 IpInfo->Ip.Ip4,
2038 NULL
2039 );
2040 IpIoCloseProtocolDestroyIpChild (
2041 IpIo->Controller,
2042 IpIo->Image,
2043 IpInfo->ChildHandle,
2044 IP_VERSION_4
2045 );
2046
2047 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);
2048
2049 } else {
2050
2051 IpInfo->Ip.Ip6->Configure (
2052 IpInfo->Ip.Ip6,
2053 NULL
2054 );
2055
2056 IpIoCloseProtocolDestroyIpChild (
2057 IpIo->Controller,
2058 IpIo->Image,
2059 IpInfo->ChildHandle,
2060 IP_VERSION_6
2061 );
2062
2063 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);
2064 }
2065
2066 FreePool (IpInfo);
2067 }
2068
2069
2070 /**
2071 Find the first IP protocol maintained in IpIo whose local
2072 address is the same as Src.
2073
2074 This function is called when the caller needs the IpIo to send data to the
2075 specified Src. The IpIo was added previously by IpIoAddIp().
2076
2077 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
2078 @param[in] IpVersion The version of the IP protocol to use, either
2079 IPv4 or IPv6.
2080 @param[in] Src The local IP address.
2081
2082 @return Pointer to the IP protocol can be used for sending purpose and its local
2083 address is the same with Src. NULL if failed.
2084
2085 **/
2086 IP_IO_IP_INFO *
2087 EFIAPI
2088 IpIoFindSender (
2089 IN OUT IP_IO **IpIo,
2090 IN UINT8 IpVersion,
2091 IN EFI_IP_ADDRESS *Src
2092 )
2093 {
2094 LIST_ENTRY *IpIoEntry;
2095 IP_IO *IpIoPtr;
2096 LIST_ENTRY *IpInfoEntry;
2097 IP_IO_IP_INFO *IpInfo;
2098
2099 if (IpIo == NULL || Src == NULL) {
2100 return NULL;
2101 }
2102
2103 if ((IpVersion != IP_VERSION_4) && (IpVersion != IP_VERSION_6)) {
2104 return NULL;
2105 }
2106
2107 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
2108 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
2109
2110 if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {
2111 continue;
2112 }
2113
2114 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
2115 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
2116 if (IpInfo->IpVersion == IP_VERSION_4){
2117
2118 if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {
2119 *IpIo = IpIoPtr;
2120 return IpInfo;
2121 }
2122
2123 } else {
2124
2125 if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {
2126 *IpIo = IpIoPtr;
2127 return IpInfo;
2128 }
2129 }
2130 }
2131 }
2132
2133 //
2134 // No match.
2135 //
2136 return NULL;
2137 }
2138
2139
2140 /**
2141 Get the ICMP error map information.
2142
2143 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2144 are not NULL, this routine will fill them.
2145
2146 @param[in] IcmpError IcmpError Type.
2147 @param[in] IpVersion The version of the IP protocol to use,
2148 either IPv4 or IPv6.
2149 @param[out] IsHard If TRUE, indicates that it is a hard error.
2150 @param[out] Notify If TRUE, SockError needs to be notified.
2151
2152 @retval EFI_UNSUPPORTED Unrecognizable ICMP error code.
2153 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2154
2155 **/
2156 EFI_STATUS
2157 EFIAPI
2158 IpIoGetIcmpErrStatus (
2159 IN UINT8 IcmpError,
2160 IN UINT8 IpVersion,
2161 OUT BOOLEAN *IsHard OPTIONAL,
2162 OUT BOOLEAN *Notify OPTIONAL
2163 )
2164 {
2165 if (IpVersion == IP_VERSION_4 ) {
2166 ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);
2167
2168 if (IsHard != NULL) {
2169 *IsHard = mIcmpErrMap[IcmpError].IsHard;
2170 }
2171
2172 if (Notify != NULL) {
2173 *Notify = mIcmpErrMap[IcmpError].Notify;
2174 }
2175
2176 switch (IcmpError) {
2177 case ICMP_ERR_UNREACH_NET:
2178 return EFI_NETWORK_UNREACHABLE;
2179
2180 case ICMP_ERR_TIMXCEED_INTRANS:
2181 case ICMP_ERR_TIMXCEED_REASS:
2182 case ICMP_ERR_UNREACH_HOST:
2183 return EFI_HOST_UNREACHABLE;
2184
2185 case ICMP_ERR_UNREACH_PROTOCOL:
2186 return EFI_PROTOCOL_UNREACHABLE;
2187
2188 case ICMP_ERR_UNREACH_PORT:
2189 return EFI_PORT_UNREACHABLE;
2190
2191 case ICMP_ERR_MSGSIZE:
2192 case ICMP_ERR_UNREACH_SRCFAIL:
2193 case ICMP_ERR_QUENCH:
2194 case ICMP_ERR_PARAMPROB:
2195 return EFI_ICMP_ERROR;
2196
2197 default:
2198 ASSERT (FALSE);
2199 return EFI_UNSUPPORTED;
2200 }
2201
2202 } else if (IpVersion == IP_VERSION_6) {
2203
2204 ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);
2205
2206 if (IsHard != NULL) {
2207 *IsHard = mIcmp6ErrMap[IcmpError].IsHard;
2208 }
2209
2210 if (Notify != NULL) {
2211 *Notify = mIcmp6ErrMap[IcmpError].Notify;
2212 }
2213
2214 switch (IcmpError) {
2215 case ICMP6_ERR_UNREACH_NET:
2216 return EFI_NETWORK_UNREACHABLE;
2217
2218 case ICMP6_ERR_UNREACH_HOST:
2219 case ICMP6_ERR_TIMXCEED_HOPLIMIT:
2220 case ICMP6_ERR_TIMXCEED_REASS:
2221 return EFI_HOST_UNREACHABLE;
2222
2223 case ICMP6_ERR_UNREACH_PROTOCOL:
2224 return EFI_PROTOCOL_UNREACHABLE;
2225
2226 case ICMP6_ERR_UNREACH_PORT:
2227 return EFI_PORT_UNREACHABLE;
2228
2229 case ICMP6_ERR_PACKAGE_TOOBIG:
2230 case ICMP6_ERR_PARAMPROB_HEADER:
2231 case ICMP6_ERR_PARAMPROB_NEXHEADER:
2232 case ICMP6_ERR_PARAMPROB_IPV6OPTION:
2233 return EFI_ICMP_ERROR;
2234
2235 default:
2236 ASSERT (FALSE);
2237 return EFI_UNSUPPORTED;
2238 }
2239
2240 } else {
2241 //
2242 // Should never be here
2243 //
2244 ASSERT (FALSE);
2245 return EFI_UNSUPPORTED;
2246 }
2247 }
2248
2249
2250 /**
2251 Refresh the remote peer's Neighbor Cache entries.
2252
2253 This function is called when the caller needs the IpIo to refresh the existing
2254 IPv6 neighbor cache entries since the neighbor is considered reachable by the
2255 node has recently received a confirmation that packets sent recently to the
2256 neighbor were received by its IP layer.
2257
2258 @param[in] IpIo Pointer to an IP_IO instance
2259 @param[in] Neighbor The IP address of the neighbor
2260 @param[in] Timeout Time in 100-ns units that this entry will
2261 remain in the neighbor cache. A value of
2262 zero means that the entry is permanent.
2263 A value of non-zero means that the entry is
2264 dynamic and will be deleted after Timeout.
2265
2266 @retval EFI_SUCCESS The operation is completed successfully.
2267 @retval EFI_NOT_STARTED The IpIo is not configured.
2268 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
2269 @retval EFI_NOT_FOUND The neighbor cache entry is not in the
2270 neighbor table.
2271 @retval EFI_UNSUPPORTED IP version is IPv4, which doesn't support neighbor cache refresh.
2272 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
2273
2274 **/
2275 EFI_STATUS
2276 EFIAPI
2277 IpIoRefreshNeighbor (
2278 IN IP_IO *IpIo,
2279 IN EFI_IP_ADDRESS *Neighbor,
2280 IN UINT32 Timeout
2281 )
2282 {
2283 EFI_IP6_PROTOCOL *Ip;
2284
2285 if (!IpIo->IsConfigured) {
2286 return EFI_NOT_STARTED;
2287 }
2288
2289 if (IpIo->IpVersion != IP_VERSION_6) {
2290 return EFI_UNSUPPORTED;
2291 }
2292
2293 Ip = IpIo->Ip.Ip6;
2294
2295 return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);
2296 }
2297