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