]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
fix ECC tool's warning
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
1 /** @file
2
3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 IpIo.c
15
16 Abstract:
17
18 The implementation of the IpIo layer.
19
20
21 **/
22
23 #include <PiDxe.h>
24
25 #include <Protocol/Udp4.h>
26
27 #include <Library/IpIoLib.h>
28 #include <Library/BaseLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/BaseMemoryLib.h>
33
34
35 #define NET_PROTO_HDR(Buf, Type) ((Type *) ((Buf)->BlockOp[0].Head))
36 #define ICMP_ERRLEN(IpHdr) \
37 (sizeof(IP4_ICMP_HEAD) + EFI_IP4_HEADER_LEN(IpHdr) + 8)
38
39 LIST_ENTRY mActiveIpIoList = {
40 &mActiveIpIoList,
41 &mActiveIpIoList
42 };
43
44 EFI_IP4_CONFIG_DATA mIpIoDefaultIpConfigData = {
45 EFI_IP_PROTO_UDP,
46 FALSE,
47 TRUE,
48 FALSE,
49 FALSE,
50 FALSE,
51 {{0, 0, 0, 0}},
52 {{0, 0, 0, 0}},
53 0,
54 255,
55 FALSE,
56 FALSE,
57 0,
58 0
59 };
60
61 ICMP_ERROR_INFO mIcmpErrMap[10] = {
62 {FALSE, TRUE},
63 {FALSE, TRUE},
64 {TRUE, TRUE},
65 {TRUE, TRUE},
66 {TRUE, TRUE},
67 {FALSE, TRUE},
68 {FALSE, TRUE},
69 {FALSE, TRUE},
70 {FALSE, FALSE},
71 {FALSE, TRUE}
72 };
73
74 VOID
75 EFIAPI
76 IpIoTransmitHandlerDpc (
77 IN VOID *Context
78 );
79
80 VOID
81 EFIAPI
82 IpIoTransmitHandler (
83 IN EFI_EVENT Event,
84 IN VOID *Context
85 );
86
87
88 /**
89 This function create an ip child ,open the IP protocol, return the opened
90 Ip protocol to Interface.
91
92 @param ControllerHandle The controller handle.
93 @param ImageHandle The image handle.
94 @param ChildHandle Pointer to the buffer to save the ip child handle.
95 @param Interface Pointer used to get the ip protocol interface.
96
97 @retval EFI_SUCCESS The ip child is created and the ip protocol
98 interface is retrieved.
99 @retval other The required operation failed.
100
101 **/
102 EFI_STATUS
103 IpIoCreateIpChildOpenProtocol (
104 IN EFI_HANDLE ControllerHandle,
105 IN EFI_HANDLE ImageHandle,
106 IN EFI_HANDLE *ChildHandle,
107 OUT VOID **Interface
108 )
109 {
110 EFI_STATUS Status;
111
112 //
113 // Create an ip child.
114 //
115 Status = NetLibCreateServiceChild (
116 ControllerHandle,
117 ImageHandle,
118 &gEfiIp4ServiceBindingProtocolGuid,
119 ChildHandle
120 );
121 if (EFI_ERROR (Status)) {
122 return Status;
123 }
124
125 //
126 // Open the ip protocol installed on the *ChildHandle.
127 //
128 Status = gBS->OpenProtocol (
129 *ChildHandle,
130 &gEfiIp4ProtocolGuid,
131 Interface,
132 ImageHandle,
133 ControllerHandle,
134 EFI_OPEN_PROTOCOL_BY_DRIVER
135 );
136 if (EFI_ERROR (Status)) {
137 //
138 // On failure, destroy the ip child.
139 //
140 NetLibDestroyServiceChild (
141 ControllerHandle,
142 ImageHandle,
143 &gEfiIp4ServiceBindingProtocolGuid,
144 *ChildHandle
145 );
146 }
147
148 return Status;
149 }
150
151
152 /**
153 This function close the previously openned ip protocol and destroy the ip child.
154
155 @param ControllerHandle The controller handle.
156 @param ImageHandle the image handle.
157 @param ChildHandle The child handle of the ip child.
158
159 @retval EFI_SUCCESS The ip protocol is closed and the relevant ip child
160 is destroyed.
161 @retval other The required operation failed.
162
163 **/
164 EFI_STATUS
165 IpIoCloseProtocolDestroyIpChild (
166 IN EFI_HANDLE ControllerHandle,
167 IN EFI_HANDLE ImageHandle,
168 IN EFI_HANDLE ChildHandle
169 )
170 {
171 EFI_STATUS Status;
172
173 //
174 // Close the previously openned ip protocol.
175 //
176 gBS->CloseProtocol (
177 ChildHandle,
178 &gEfiIp4ProtocolGuid,
179 ImageHandle,
180 ControllerHandle
181 );
182
183 //
184 // Destroy the ip child.
185 //
186 Status = NetLibDestroyServiceChild (
187 ControllerHandle,
188 ImageHandle,
189 &gEfiIp4ServiceBindingProtocolGuid,
190 ChildHandle
191 );
192
193 return Status;
194 }
195
196
197 /**
198 Handle ICMP packets.
199
200 @param IpIo Pointer to the IP_IO instance.
201 @param Pkt Pointer to the ICMP packet.
202 @param Session Pointer to the net session of this ICMP packet.
203
204 @retval EFI_SUCCESS The ICMP packet is handled successfully.
205 @retval EFI_ABORTED This type of ICMP packet is not supported.
206
207 **/
208 EFI_STATUS
209 IpIoIcmpHandler (
210 IN IP_IO *IpIo,
211 IN NET_BUF *Pkt,
212 IN EFI_NET_SESSION_DATA *Session
213 )
214 {
215 IP4_ICMP_ERROR_HEAD *IcmpHdr;
216 EFI_IP4_HEADER *IpHdr;
217 ICMP_ERROR IcmpErr;
218 UINT8 *PayLoadHdr;
219 UINT8 Type;
220 UINT8 Code;
221 UINT32 TrimBytes;
222
223 IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);
224 IpHdr = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);
225
226 //
227 // Check the ICMP packet length.
228 //
229 if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {
230
231 return EFI_ABORTED;
232 }
233
234 Type = IcmpHdr->Head.Type;
235 Code = IcmpHdr->Head.Code;
236
237 //
238 // Analyze the ICMP Error in this ICMP pkt
239 //
240 switch (Type) {
241 case ICMP_TYPE_UNREACH:
242 switch (Code) {
243 case ICMP_CODE_UNREACH_NET:
244 case ICMP_CODE_UNREACH_HOST:
245 case ICMP_CODE_UNREACH_PROTOCOL:
246 case ICMP_CODE_UNREACH_PORT:
247 case ICMP_CODE_UNREACH_SRCFAIL:
248 IcmpErr = (ICMP_ERROR) (ICMP_ERR_UNREACH_NET + Code);
249
250 break;
251
252 case ICMP_CODE_UNREACH_NEEDFRAG:
253 IcmpErr = ICMP_ERR_MSGSIZE;
254
255 break;
256
257 case ICMP_CODE_UNREACH_NET_UNKNOWN:
258 case ICMP_CODE_UNREACH_NET_PROHIB:
259 case ICMP_CODE_UNREACH_TOSNET:
260 IcmpErr = ICMP_ERR_UNREACH_NET;
261
262 break;
263
264 case ICMP_CODE_UNREACH_HOST_UNKNOWN:
265 case ICMP_CODE_UNREACH_ISOLATED:
266 case ICMP_CODE_UNREACH_HOST_PROHIB:
267 case ICMP_CODE_UNREACH_TOSHOST:
268 IcmpErr = ICMP_ERR_UNREACH_HOST;
269
270 break;
271
272 default:
273 return EFI_ABORTED;
274
275 break;
276 }
277
278 break;
279
280 case ICMP_TYPE_TIMXCEED:
281 if (Code > 1) {
282 return EFI_ABORTED;
283 }
284
285 IcmpErr = (ICMP_ERROR) (Code + ICMP_ERR_TIMXCEED_INTRANS);
286
287 break;
288
289 case ICMP_TYPE_PARAMPROB:
290 if (Code > 1) {
291 return EFI_ABORTED;
292 }
293
294 IcmpErr = ICMP_ERR_PARAMPROB;
295
296 break;
297
298 case ICMP_TYPE_SOURCEQUENCH:
299 if (Code != 0) {
300 return EFI_ABORTED;
301 }
302
303 IcmpErr = ICMP_ERR_QUENCH;
304
305 break;
306
307 default:
308 return EFI_ABORTED;
309
310 break;
311 }
312
313 //
314 // Notify user the ICMP pkt only containing payload except
315 // IP and ICMP header
316 //
317 PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));
318 TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
319
320 NetbufTrim (Pkt, TrimBytes, TRUE);
321
322 IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
323
324 return EFI_SUCCESS;
325 }
326
327
328 /**
329 Ext free function for net buffer. This function is
330 called when the net buffer is freed. It is used to
331 signal the recycle event to notify IP to recycle the
332 data buffer.
333
334 @param Event The event to be signaled.
335
336 @return None.
337
338 **/
339 VOID
340 IpIoExtFree (
341 IN VOID *Event
342 )
343 {
344 gBS->SignalEvent ((EFI_EVENT) Event);
345 }
346
347
348 /**
349 Create a send entry to wrap a packet before sending
350 out it through IP.
351
352 @param IpIo Pointer to the IP_IO instance.
353 @param Pkt Pointer to the packet.
354 @param Sender Pointer to the IP sender.
355 @param NotifyData Pointer to the notify data.
356 @param Dest Pointer to the destination IP address.
357 @param Override Pointer to the overriden IP_IO data.
358
359 @return Pointer to the data structure created to wrap the packet. If NULL,
360 @return resource limit occurred.
361
362 **/
363 IP_IO_SEND_ENTRY *
364 IpIoCreateSndEntry (
365 IN IP_IO *IpIo,
366 IN NET_BUF *Pkt,
367 IN EFI_IP4_PROTOCOL *Sender,
368 IN VOID *Context OPTIONAL,
369 IN VOID *NotifyData OPTIONAL,
370 IN IP4_ADDR Dest,
371 IN IP_IO_OVERRIDE *Override
372 )
373 {
374 IP_IO_SEND_ENTRY *SndEntry;
375 EFI_IP4_COMPLETION_TOKEN *SndToken;
376 EFI_IP4_TRANSMIT_DATA *TxData;
377 EFI_STATUS Status;
378 EFI_IP4_OVERRIDE_DATA *OverrideData;
379 volatile UINT32 Index;
380
381 //
382 // Allocate resource for SndEntry
383 //
384 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
385 if (NULL == SndEntry) {
386 return NULL;
387 }
388
389 //
390 // Allocate resource for SndToken
391 //
392 SndToken = AllocatePool (sizeof (EFI_IP4_COMPLETION_TOKEN));
393 if (NULL == SndToken) {
394 goto ReleaseSndEntry;
395 }
396
397 Status = gBS->CreateEvent (
398 EVT_NOTIFY_SIGNAL,
399 TPL_NOTIFY,
400 IpIoTransmitHandler,
401 SndEntry,
402 &(SndToken->Event)
403 );
404 if (EFI_ERROR (Status)) {
405 goto ReleaseSndToken;
406 }
407
408 //
409 // Allocate resource for TxData
410 //
411 TxData = AllocatePool (
412 sizeof (EFI_IP4_TRANSMIT_DATA) +
413 sizeof (EFI_IP4_FRAGMENT_DATA) * (Pkt->BlockOpNum - 1)
414 );
415
416 if (NULL == TxData) {
417 goto ReleaseEvent;
418 }
419
420 //
421 // Allocate resource for OverrideData if needed
422 //
423 OverrideData = NULL;
424 if (NULL != Override) {
425
426 OverrideData = AllocatePool (sizeof (EFI_IP4_OVERRIDE_DATA));
427 if (NULL == OverrideData) {
428 goto ReleaseResource;
429 }
430 //
431 // Set the fields of OverrideData
432 //
433 CopyMem (OverrideData, Override, sizeof (*OverrideData));
434 }
435
436 //
437 // Set the fields of TxData
438 //
439 CopyMem (&TxData->DestinationAddress, &Dest, sizeof (EFI_IPv4_ADDRESS));
440 TxData->OverrideData = OverrideData;
441 TxData->OptionsLength = 0;
442 TxData->OptionsBuffer = NULL;
443 TxData->TotalDataLength = Pkt->TotalSize;
444 TxData->FragmentCount = Pkt->BlockOpNum;
445
446
447 for (Index = 0; Index < Pkt->BlockOpNum; Index++) {
448 TxData->FragmentTable[Index].FragmentBuffer = Pkt->BlockOp[Index].Head;
449 TxData->FragmentTable[Index].FragmentLength = Pkt->BlockOp[Index].Size;
450 }
451
452 //
453 // Set the fields of SndToken
454 //
455 SndToken->Packet.TxData = TxData;
456
457 //
458 // Set the fields of SndEntry
459 //
460 SndEntry->IpIo = IpIo;
461 SndEntry->Ip = Sender;
462 SndEntry->Context = Context;
463 SndEntry->NotifyData = NotifyData;
464
465 SndEntry->Pkt = Pkt;
466 NET_GET_REF (Pkt);
467
468 SndEntry->SndToken = SndToken;
469
470 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
471
472 return SndEntry;
473
474 ReleaseResource:
475 gBS->FreePool (TxData);
476
477 ReleaseEvent:
478 gBS->CloseEvent (SndToken->Event);
479
480 ReleaseSndToken:
481 gBS->FreePool (SndToken);
482
483 ReleaseSndEntry:
484 gBS->FreePool (SndEntry);
485
486 return NULL;
487 }
488
489
490 /**
491 Destroy the SndEntry.
492
493 @param SndEntry Pointer to the send entry to be destroyed.
494
495 @return None.
496
497 **/
498 VOID
499 IpIoDestroySndEntry (
500 IN IP_IO_SEND_ENTRY *SndEntry
501 )
502 {
503 EFI_IP4_TRANSMIT_DATA *TxData;
504
505 TxData = SndEntry->SndToken->Packet.TxData;
506
507 if (NULL != TxData->OverrideData) {
508 gBS->FreePool (TxData->OverrideData);
509 }
510
511 gBS->FreePool (TxData);
512 NetbufFree (SndEntry->Pkt);
513 gBS->CloseEvent (SndEntry->SndToken->Event);
514
515 gBS->FreePool (SndEntry->SndToken);
516 RemoveEntryList (&SndEntry->Entry);
517
518 gBS->FreePool (SndEntry);
519 }
520
521
522 /**
523 Notify function for IP transmit token.
524
525 @param Context The context passed in by the event notifier.
526
527 @return None.
528
529 **/
530 VOID
531 EFIAPI
532 IpIoTransmitHandlerDpc (
533 IN VOID *Context
534 )
535 {
536 IP_IO *IpIo;
537 IP_IO_SEND_ENTRY *SndEntry;
538
539 SndEntry = (IP_IO_SEND_ENTRY *) Context;
540
541 IpIo = SndEntry->IpIo;
542
543 if (IpIo->PktSentNotify && SndEntry->NotifyData) {
544 IpIo->PktSentNotify (
545 SndEntry->SndToken->Status,
546 SndEntry->Context,
547 SndEntry->Ip,
548 SndEntry->NotifyData
549 );
550 }
551
552 IpIoDestroySndEntry (SndEntry);
553 }
554
555 /**
556 Notify function for IP transmit token.
557
558 @param Event The event signaled.
559 @param Context The context passed in by the event notifier.
560
561 @return None.
562
563 **/
564
565 VOID
566 EFIAPI
567 IpIoTransmitHandler (
568 IN EFI_EVENT Event,
569 IN VOID *Context
570 )
571 {
572 //
573 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
574 //
575 NetLibQueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
576 }
577
578
579 /**
580 The dummy handler for the dummy IP receive token.
581
582 @param Context The context passed in by the event notifier.
583
584 @return None.
585
586 **/
587 VOID
588 EFIAPI
589 IpIoDummyHandlerDpc (
590 IN VOID *Context
591 )
592 {
593 IP_IO_IP_INFO *IpInfo;
594 EFI_IP4_COMPLETION_TOKEN *DummyToken;
595
596 IpInfo = (IP_IO_IP_INFO *) Context;
597 DummyToken = &(IpInfo->DummyRcvToken);
598
599 if (EFI_ABORTED == DummyToken->Status) {
600 //
601 // The reception is actively aborted by the consumer, directly return.
602 //
603 return;
604 } else if (EFI_SUCCESS == DummyToken->Status) {
605 ASSERT (DummyToken->Packet.RxData);
606
607 gBS->SignalEvent (DummyToken->Packet.RxData->RecycleSignal);
608 }
609
610 IpInfo->Ip->Receive (IpInfo->Ip, DummyToken);
611 }
612
613
614 /**
615 Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK.
616
617 @param Event The event signaled.
618 @param Context The context passed in by the event notifier.
619
620 @return None.
621
622 **/
623 VOID
624 EFIAPI
625 IpIoDummyHandler (
626 IN EFI_EVENT Event,
627 IN VOID *Context
628 )
629 {
630 //
631 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
632 //
633 NetLibQueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
634 }
635
636
637 /**
638 Notify function for the IP receive token, used to process
639 the received IP packets.
640
641 @param Context The context passed in by the event notifier.
642
643 @return None.
644
645 **/
646 VOID
647 EFIAPI
648 IpIoListenHandlerDpc (
649 IN VOID *Context
650 )
651 {
652 IP_IO *IpIo;
653 EFI_STATUS Status;
654 EFI_IP4_RECEIVE_DATA *RxData;
655 EFI_IP4_PROTOCOL *Ip;
656 EFI_NET_SESSION_DATA Session;
657 NET_BUF *Pkt;
658
659 IpIo = (IP_IO *) Context;
660
661 Ip = IpIo->Ip;
662 Status = IpIo->RcvToken.Status;
663 RxData = IpIo->RcvToken.Packet.RxData;
664
665 if (EFI_ABORTED == Status) {
666 //
667 // The reception is actively aborted by the consumer, directly return.
668 //
669 return;
670 }
671
672 if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {
673 //
674 // Only process the normal packets and the icmp error packets, if RxData is NULL
675 // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
676 // this should be a bug of the low layer (IP).
677 //
678 goto Resume;
679 }
680
681 if (NULL == IpIo->PktRcvdNotify) {
682 goto CleanUp;
683 }
684
685 if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&
686 !Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
687 //
688 // The source address is not zero and it's not a unicast IP address, discard it.
689 //
690 goto CleanUp;
691 }
692
693 //
694 // Create a netbuffer representing packet
695 //
696 Pkt = NetbufFromExt (
697 (NET_FRAGMENT *) RxData->FragmentTable,
698 RxData->FragmentCount,
699 0,
700 0,
701 IpIoExtFree,
702 RxData->RecycleSignal
703 );
704 if (NULL == Pkt) {
705 goto CleanUp;
706 }
707
708 //
709 // Create a net session
710 //
711 Session.Source = EFI_IP4 (RxData->Header->SourceAddress);
712 Session.Dest = EFI_IP4 (RxData->Header->DestinationAddress);
713 Session.IpHdr = RxData->Header;
714
715 if (EFI_SUCCESS == Status) {
716
717 IpIo->PktRcvdNotify (EFI_SUCCESS, (ICMP_ERROR) 0, &Session, Pkt, IpIo->RcvdContext);
718 } else {
719 //
720 // Status is EFI_ICMP_ERROR
721 //
722 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
723 if (EFI_ERROR (Status)) {
724 NetbufFree (Pkt);
725 }
726 }
727
728 goto Resume;
729
730 CleanUp:
731 gBS->SignalEvent (RxData->RecycleSignal);
732
733 Resume:
734 Ip->Receive (Ip, &(IpIo->RcvToken));
735 }
736
737
738 /**
739 Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
740
741 @param Event The event signaled.
742 @param Context The context passed in by the event notifier.
743
744 @return None.
745
746 **/
747 VOID
748 EFIAPI
749 IpIoListenHandler (
750 IN EFI_EVENT Event,
751 IN VOID *Context
752 )
753 {
754 //
755 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
756 //
757 NetLibQueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
758 }
759
760
761 /**
762 Create a new IP_IO instance.
763
764 @param Image The image handle of an IP_IO consumer protocol.
765 @param Controller The controller handle of an IP_IO consumer protocol
766 installed on.
767
768 @return Pointer to a newly created IP_IO instance.
769
770 **/
771 IP_IO *
772 EFIAPI
773 IpIoCreate (
774 IN EFI_HANDLE Image,
775 IN EFI_HANDLE Controller
776 )
777 {
778 EFI_STATUS Status;
779 IP_IO *IpIo;
780
781 IpIo = AllocateZeroPool (sizeof (IP_IO));
782 if (NULL == IpIo) {
783 return NULL;
784 }
785
786 InitializeListHead (&(IpIo->PendingSndList));
787 InitializeListHead (&(IpIo->IpList));
788 IpIo->Controller = Controller;
789 IpIo->Image = Image;
790
791 Status = gBS->CreateEvent (
792 EVT_NOTIFY_SIGNAL,
793 TPL_NOTIFY,
794 IpIoListenHandler,
795 IpIo,
796 &(IpIo->RcvToken.Event)
797 );
798 if (EFI_ERROR (Status)) {
799 goto ReleaseIpIo;
800 }
801
802 //
803 // Create an IP child and open IP protocol
804 //
805 Status = IpIoCreateIpChildOpenProtocol (
806 Controller,
807 Image,
808 &IpIo->ChildHandle,
809 (VOID **)&(IpIo->Ip)
810 );
811 if (EFI_ERROR (Status)) {
812 goto ReleaseIpIo;
813 }
814
815 return IpIo;
816
817 ReleaseIpIo:
818
819 if (NULL != IpIo->RcvToken.Event) {
820 gBS->CloseEvent (IpIo->RcvToken.Event);
821 }
822
823 gBS->FreePool (IpIo);
824
825 return NULL;
826 }
827
828
829 /**
830 Open an IP_IO instance for use.
831
832 @param IpIo Pointer to an IP_IO instance that needs to open.
833 @param OpenData The configuration data for the IP_IO instance.
834
835 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
836 successfully.
837 @retval other Error condition occurred.
838
839 **/
840 EFI_STATUS
841 EFIAPI
842 IpIoOpen (
843 IN IP_IO *IpIo,
844 IN IP_IO_OPEN_DATA *OpenData
845 )
846 {
847 EFI_STATUS Status;
848 EFI_IP4_PROTOCOL *Ip;
849
850 if (IpIo->IsConfigured) {
851 return EFI_ACCESS_DENIED;
852 }
853
854 Ip = IpIo->Ip;
855
856 //
857 // configure ip
858 //
859 Status = Ip->Configure (Ip, &OpenData->IpConfigData);
860 if (EFI_ERROR (Status)) {
861 return Status;
862 }
863
864 //
865 // bugbug: to delete the default route entry in this Ip, if it is:
866 // (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
867 // its code
868 //
869 Status = Ip->Routes (Ip, TRUE, &mZeroIp4Addr, &mZeroIp4Addr, &mZeroIp4Addr);
870
871 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
872 return Status;
873 }
874
875 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
876 IpIo->PktSentNotify = OpenData->PktSentNotify;
877
878 IpIo->RcvdContext = OpenData->RcvdContext;
879 IpIo->SndContext = OpenData->SndContext;
880
881 IpIo->Protocol = OpenData->IpConfigData.DefaultProtocol;
882
883 //
884 // start to listen incoming packet
885 //
886 Status = Ip->Receive (Ip, &(IpIo->RcvToken));
887 if (EFI_ERROR (Status)) {
888 Ip->Configure (Ip, NULL);
889 goto ErrorExit;
890 }
891
892 IpIo->IsConfigured = TRUE;
893 InsertTailList (&mActiveIpIoList, &IpIo->Entry);
894
895 ErrorExit:
896
897 return Status;
898 }
899
900
901 /**
902 Stop an IP_IO instance.
903
904 @param IpIo Pointer to the IP_IO instance that needs to stop.
905
906 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
907 @retval other Error condition occurred.
908
909 **/
910 EFI_STATUS
911 IpIoStop (
912 IN IP_IO *IpIo
913 )
914 {
915 EFI_STATUS Status;
916 EFI_IP4_PROTOCOL *Ip;
917 IP_IO_IP_INFO *IpInfo;
918
919 if (!IpIo->IsConfigured) {
920 return EFI_SUCCESS;
921 }
922
923 //
924 // Remove the IpIo from the active IpIo list.
925 //
926 RemoveEntryList (&IpIo->Entry);
927
928 Ip = IpIo->Ip;
929
930 //
931 // Configure NULL Ip
932 //
933 Status = Ip->Configure (Ip, NULL);
934 if (EFI_ERROR (Status)) {
935 return Status;
936 }
937
938 IpIo->IsConfigured = FALSE;
939
940 //
941 // Detroy the Ip List used by IpIo
942 //
943
944 while (!IsListEmpty (&(IpIo->IpList))) {
945 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
946
947 IpIoRemoveIp (IpIo, IpInfo);
948 }
949
950 //
951 // All pending snd tokens should be flushed by reseting the IP instances.
952 //
953 ASSERT (IsListEmpty (&IpIo->PendingSndList));
954
955 //
956 // Close the receive event.
957 //
958 gBS->CloseEvent (IpIo->RcvToken.Event);
959
960 return EFI_SUCCESS;
961 }
962
963
964 /**
965 Destroy an IP_IO instance.
966
967 @param IpIo Pointer to the IP_IO instance that needs to
968 destroy.
969
970 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
971 @retval other Error condition occurred.
972
973 **/
974 EFI_STATUS
975 EFIAPI
976 IpIoDestroy (
977 IN IP_IO *IpIo
978 )
979 {
980 //
981 // Stop the IpIo.
982 //
983 IpIoStop (IpIo);
984
985 //
986 // Close the IP protocol and destroy the child.
987 //
988 IpIoCloseProtocolDestroyIpChild (IpIo->Controller, IpIo->Image, IpIo->ChildHandle);
989
990 gBS->FreePool (IpIo);
991
992 return EFI_SUCCESS;
993 }
994
995
996 /**
997 Send out an IP packet.
998
999 @param IpIo Pointer to an IP_IO instance used for sending IP
1000 packet.
1001 @param Pkt Pointer to the IP packet to be sent.
1002 @param Sender The IP protocol instance used for sending.
1003 @param NotifyData
1004 @param Dest The destination IP address to send this packet to.
1005 @param OverrideData The data to override some configuration of the IP
1006 instance used for sending.
1007
1008 @retval EFI_SUCCESS The operation is completed successfully.
1009 @retval EFI_NOT_STARTED The IpIo is not configured.
1010 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1011
1012 **/
1013 EFI_STATUS
1014 EFIAPI
1015 IpIoSend (
1016 IN IP_IO *IpIo,
1017 IN NET_BUF *Pkt,
1018 IN IP_IO_IP_INFO *Sender,
1019 IN VOID *Context OPTIONAL,
1020 IN VOID *NotifyData OPTIONAL,
1021 IN IP4_ADDR Dest,
1022 IN IP_IO_OVERRIDE *OverrideData
1023 )
1024 {
1025 EFI_STATUS Status;
1026 EFI_IP4_PROTOCOL *Ip;
1027 IP_IO_SEND_ENTRY *SndEntry;
1028
1029 if (!IpIo->IsConfigured) {
1030 return EFI_NOT_STARTED;
1031 }
1032
1033 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
1034
1035 //
1036 // create a new SndEntry
1037 //
1038 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
1039 if (NULL == SndEntry) {
1040 return EFI_OUT_OF_RESOURCES;
1041 }
1042
1043 //
1044 // Send this Packet
1045 //
1046 Status = Ip->Transmit (Ip, SndEntry->SndToken);
1047 if (EFI_ERROR (Status)) {
1048 IpIoDestroySndEntry (SndEntry);
1049 }
1050
1051 return Status;
1052 }
1053
1054
1055 /**
1056 Cancel the IP transmit token which wraps this Packet.
1057
1058 @param IpIo Pointer to the IP_IO instance.
1059 @param Packet Pointer to the packet to cancel.
1060
1061 @return N/A.
1062
1063 **/
1064 VOID
1065 EFIAPI
1066 IpIoCancelTxToken (
1067 IN IP_IO *IpIo,
1068 IN VOID *Packet
1069 )
1070 {
1071 LIST_ENTRY *Node;
1072 IP_IO_SEND_ENTRY *SndEntry;
1073 EFI_IP4_PROTOCOL *Ip;
1074
1075 ASSERT (IpIo && Packet);
1076
1077 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
1078
1079 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
1080
1081 if (SndEntry->Pkt == Packet) {
1082
1083 Ip = SndEntry->Ip;
1084 Ip->Cancel (Ip, SndEntry->SndToken);
1085
1086 break;
1087 }
1088 }
1089
1090 }
1091
1092
1093 /**
1094 Add a new IP instance for sending data.
1095
1096 @param IpIo Pointer to a IP_IO instance to add a new IP
1097 instance for sending purpose.
1098
1099 @return Pointer to the created IP_IO_IP_INFO structure, NULL is failed.
1100
1101 **/
1102 IP_IO_IP_INFO *
1103 EFIAPI
1104 IpIoAddIp (
1105 IN IP_IO *IpIo
1106 )
1107 {
1108 EFI_STATUS Status;
1109 IP_IO_IP_INFO *IpInfo;
1110
1111 ASSERT (IpIo);
1112
1113 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
1114 if (IpInfo == NULL) {
1115 return IpInfo;
1116 }
1117
1118 //
1119 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1120 // instance.
1121 //
1122 InitializeListHead (&IpInfo->Entry);
1123 IpInfo->ChildHandle = NULL;
1124 IpInfo->Addr = 0;
1125 IpInfo->SubnetMask = 0;
1126 IpInfo->RefCnt = 1;
1127
1128 //
1129 // Create the IP instance and open the Ip4 protocol.
1130 //
1131 Status = IpIoCreateIpChildOpenProtocol (
1132 IpIo->Controller,
1133 IpIo->Image,
1134 &IpInfo->ChildHandle,
1135 (VOID **) &IpInfo->Ip
1136 );
1137 if (EFI_ERROR (Status)) {
1138 goto ReleaseIpInfo;
1139 }
1140
1141 //
1142 // Create the event for the DummyRcvToken.
1143 //
1144 Status = gBS->CreateEvent (
1145 EVT_NOTIFY_SIGNAL,
1146 TPL_NOTIFY,
1147 IpIoDummyHandler,
1148 IpInfo,
1149 &IpInfo->DummyRcvToken.Event
1150 );
1151 if (EFI_ERROR (Status)) {
1152 goto ReleaseIpChild;
1153 }
1154
1155 //
1156 // Link this IpInfo into the IpIo.
1157 //
1158 InsertTailList (&IpIo->IpList, &IpInfo->Entry);
1159
1160 return IpInfo;
1161
1162 ReleaseIpChild:
1163
1164 IpIoCloseProtocolDestroyIpChild (
1165 IpIo->Controller,
1166 IpIo->Image,
1167 IpInfo->ChildHandle
1168 );
1169
1170 ReleaseIpInfo:
1171
1172 gBS->FreePool (IpInfo);
1173
1174 return NULL;
1175 }
1176
1177
1178 /**
1179 Configure the IP instance of this IpInfo and start the receiving if Ip4ConfigData
1180 is not NULL.
1181
1182 @param IpInfo Pointer to the IP_IO_IP_INFO instance.
1183 @param Ip4ConfigData The IP4 configure data used to configure the ip
1184 instance, if NULL the ip instance is reseted. If
1185 UseDefaultAddress is set to TRUE, and the configure
1186 operation succeeds, the default address information
1187 is written back in this Ip4ConfigData.
1188
1189 @retval EFI_STATUS The status returned by IP4->Configure or
1190 IP4->Receive.
1191
1192 **/
1193 EFI_STATUS
1194 EFIAPI
1195 IpIoConfigIp (
1196 IN IP_IO_IP_INFO *IpInfo,
1197 IN OUT EFI_IP4_CONFIG_DATA *Ip4ConfigData OPTIONAL
1198 )
1199 {
1200 EFI_STATUS Status;
1201 EFI_IP4_PROTOCOL *Ip;
1202 EFI_IP4_MODE_DATA Ip4ModeData;
1203
1204 ASSERT (IpInfo);
1205
1206 if (IpInfo->RefCnt > 1) {
1207 //
1208 // This IP instance is shared, don't reconfigure it until it has only one
1209 // consumer. Currently, only the tcp children cloned from their passive parent
1210 // will share the same IP. So this cases only happens while Ip4ConfigData is NULL,
1211 // let the last consumer clean the IP instance.
1212 //
1213 return EFI_SUCCESS;
1214 }
1215
1216 Ip = IpInfo->Ip;
1217
1218 Status = Ip->Configure (Ip, Ip4ConfigData);
1219 if (EFI_ERROR (Status)) {
1220 goto OnExit;
1221 }
1222
1223 if (Ip4ConfigData != NULL) {
1224
1225 if (Ip4ConfigData->UseDefaultAddress) {
1226 Ip->GetModeData (Ip, &Ip4ModeData, NULL, NULL);
1227
1228 Ip4ConfigData->StationAddress = Ip4ModeData.ConfigData.StationAddress;
1229 Ip4ConfigData->SubnetMask = Ip4ModeData.ConfigData.SubnetMask;
1230 }
1231
1232 CopyMem (&IpInfo->Addr, &Ip4ConfigData->StationAddress, sizeof (IP4_ADDR));
1233 CopyMem (&IpInfo->SubnetMask, &Ip4ConfigData->SubnetMask, sizeof (IP4_ADDR));
1234
1235 Status = Ip->Receive (Ip, &IpInfo->DummyRcvToken);
1236 if (EFI_ERROR (Status)) {
1237 Ip->Configure (Ip, NULL);
1238 }
1239 } else {
1240
1241 //
1242 // The IP instance is reseted, set the stored Addr and SubnetMask to zero.
1243 //
1244 IpInfo->Addr = 0;
1245 IpInfo->SubnetMask =0;
1246 }
1247
1248 OnExit:
1249
1250 return Status;
1251 }
1252
1253
1254 /**
1255 Destroy an IP instance maintained in IpIo->IpList for
1256 sending purpose.
1257
1258 @param IpIo Pointer to the IP_IO instance.
1259 @param IpInfo Pointer to the IpInfo to be removed.
1260
1261 @return None.
1262
1263 **/
1264 VOID
1265 EFIAPI
1266 IpIoRemoveIp (
1267 IN IP_IO *IpIo,
1268 IN IP_IO_IP_INFO *IpInfo
1269 )
1270 {
1271 ASSERT (IpInfo->RefCnt > 0);
1272
1273 NET_PUT_REF (IpInfo);
1274
1275 if (IpInfo->RefCnt > 0) {
1276
1277 return;
1278 }
1279
1280 RemoveEntryList (&IpInfo->Entry);
1281
1282 IpInfo->Ip->Configure (IpInfo->Ip, NULL);
1283
1284 IpIoCloseProtocolDestroyIpChild (IpIo->Controller, IpIo->Image, IpInfo->ChildHandle);
1285
1286 gBS->CloseEvent (IpInfo->DummyRcvToken.Event);
1287
1288 gBS->FreePool (IpInfo);
1289 }
1290
1291
1292 /**
1293 Find the first IP protocol maintained in IpIo whose local
1294 address is the same with Src.
1295
1296 @param IpIo Pointer to the pointer of the IP_IO instance.
1297 @param Src The local IP address.
1298
1299 @return Pointer to the IP protocol can be used for sending purpose and its local
1300 @return address is the same with Src.
1301
1302 **/
1303 IP_IO_IP_INFO *
1304 EFIAPI
1305 IpIoFindSender (
1306 IN OUT IP_IO **IpIo,
1307 IN IP4_ADDR Src
1308 )
1309 {
1310 LIST_ENTRY *IpIoEntry;
1311 IP_IO *IpIoPtr;
1312 LIST_ENTRY *IpInfoEntry;
1313 IP_IO_IP_INFO *IpInfo;
1314
1315 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
1316 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
1317
1318 if ((*IpIo != NULL) && (*IpIo != IpIoPtr)) {
1319 continue;
1320 }
1321
1322 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
1323 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
1324
1325 if (IpInfo->Addr == Src) {
1326 *IpIo = IpIoPtr;
1327 return IpInfo;
1328 }
1329 }
1330 }
1331
1332 //
1333 // No match.
1334 //
1335 return NULL;
1336 }
1337
1338
1339 /**
1340 Get the ICMP error map information, the ErrorStatus will be returned.
1341 The IsHard and Notify are optional. If they are not NULL, this rouine will
1342 fill them.
1343 We move IcmpErrMap[] to local variable to enable EBC build.
1344
1345 @param IcmpError IcmpError Type
1346 @param IsHard Whether it is a hard error
1347 @param Notify Whether it need to notify SockError
1348
1349 @return ICMP Error Status
1350
1351 **/
1352 EFI_STATUS
1353 EFIAPI
1354 IpIoGetIcmpErrStatus (
1355 IN ICMP_ERROR IcmpError,
1356 OUT BOOLEAN *IsHard, OPTIONAL
1357 OUT BOOLEAN *Notify OPTIONAL
1358 )
1359 {
1360 ASSERT ((IcmpError >= ICMP_ERR_UNREACH_NET) && (IcmpError <= ICMP_ERR_PARAMPROB));
1361
1362 if (IsHard != NULL) {
1363 *IsHard = mIcmpErrMap[IcmpError].IsHard;
1364 }
1365
1366 if (Notify != NULL) {
1367 *Notify = mIcmpErrMap[IcmpError].Notify;
1368 }
1369
1370 switch (IcmpError) {
1371 case ICMP_ERR_UNREACH_NET:
1372 return EFI_NETWORK_UNREACHABLE;
1373
1374 case ICMP_ERR_TIMXCEED_INTRANS:
1375 case ICMP_ERR_TIMXCEED_REASS:
1376 case ICMP_ERR_UNREACH_HOST:
1377 return EFI_HOST_UNREACHABLE;
1378
1379 case ICMP_ERR_UNREACH_PROTOCOL:
1380 return EFI_PROTOCOL_UNREACHABLE;
1381
1382 case ICMP_ERR_UNREACH_PORT:
1383 return EFI_PORT_UNREACHABLE;
1384
1385 case ICMP_ERR_MSGSIZE:
1386 case ICMP_ERR_UNREACH_SRCFAIL:
1387 case ICMP_ERR_QUENCH:
1388 case ICMP_ERR_PARAMPROB:
1389 return EFI_ICMP_ERROR;
1390 }
1391
1392 //
1393 // will never run here!
1394 //
1395 ASSERT (FALSE);
1396 return EFI_UNSUPPORTED;
1397 }
1398