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