]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
enhanced function header
[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 and return the opened
90 IP protocol as 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 This function handles 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 Free function for receive token of IP_IO. It is used to
330 signal the recycle event to notify IP to recycle the
331 data buffer.
332
333 @param Event The event to be signaled.
334
335 **/
336 VOID
337 IpIoExtFree (
338 IN VOID *Event
339 )
340 {
341 gBS->SignalEvent ((EFI_EVENT) Event);
342 }
343
344
345 /**
346 Create a send entry to wrap a packet before sending
347 out it through IP.
348
349 @param IpIo Pointer to the IP_IO instance.
350 @param Pkt Pointer to the packet.
351 @param Sender Pointer to the IP sender.
352 @param NotifyData Pointer to the notify data.
353 @param Dest Pointer to the destination IP address.
354 @param Override Pointer to the overriden IP_IO data.
355
356 @return Pointer to the data structure created to wrap the packet. If NULL,
357 resource limit occurred.
358
359 **/
360 IP_IO_SEND_ENTRY *
361 IpIoCreateSndEntry (
362 IN IP_IO *IpIo,
363 IN NET_BUF *Pkt,
364 IN EFI_IP4_PROTOCOL *Sender,
365 IN VOID *Context OPTIONAL,
366 IN VOID *NotifyData OPTIONAL,
367 IN IP4_ADDR Dest,
368 IN IP_IO_OVERRIDE *Override
369 )
370 {
371 IP_IO_SEND_ENTRY *SndEntry;
372 EFI_IP4_COMPLETION_TOKEN *SndToken;
373 EFI_IP4_TRANSMIT_DATA *TxData;
374 EFI_STATUS Status;
375 EFI_IP4_OVERRIDE_DATA *OverrideData;
376 volatile UINT32 Index;
377
378 //
379 // Allocate resource for SndEntry
380 //
381 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
382 if (NULL == SndEntry) {
383 return NULL;
384 }
385
386 //
387 // Allocate resource for SndToken
388 //
389 SndToken = AllocatePool (sizeof (EFI_IP4_COMPLETION_TOKEN));
390 if (NULL == SndToken) {
391 goto ReleaseSndEntry;
392 }
393
394 Status = gBS->CreateEvent (
395 EVT_NOTIFY_SIGNAL,
396 TPL_NOTIFY,
397 IpIoTransmitHandler,
398 SndEntry,
399 &(SndToken->Event)
400 );
401 if (EFI_ERROR (Status)) {
402 goto ReleaseSndToken;
403 }
404
405 //
406 // Allocate resource for TxData
407 //
408 TxData = AllocatePool (
409 sizeof (EFI_IP4_TRANSMIT_DATA) +
410 sizeof (EFI_IP4_FRAGMENT_DATA) * (Pkt->BlockOpNum - 1)
411 );
412
413 if (NULL == TxData) {
414 goto ReleaseEvent;
415 }
416
417 //
418 // Allocate resource for OverrideData if needed
419 //
420 OverrideData = NULL;
421 if (NULL != Override) {
422
423 OverrideData = AllocatePool (sizeof (EFI_IP4_OVERRIDE_DATA));
424 if (NULL == OverrideData) {
425 goto ReleaseResource;
426 }
427 //
428 // Set the fields of OverrideData
429 //
430 CopyMem (OverrideData, Override, sizeof (*OverrideData));
431 }
432
433 //
434 // Set the fields of TxData
435 //
436 CopyMem (&TxData->DestinationAddress, &Dest, sizeof (EFI_IPv4_ADDRESS));
437 TxData->OverrideData = OverrideData;
438 TxData->OptionsLength = 0;
439 TxData->OptionsBuffer = NULL;
440 TxData->TotalDataLength = Pkt->TotalSize;
441 TxData->FragmentCount = Pkt->BlockOpNum;
442
443
444 for (Index = 0; Index < Pkt->BlockOpNum; Index++) {
445 TxData->FragmentTable[Index].FragmentBuffer = Pkt->BlockOp[Index].Head;
446 TxData->FragmentTable[Index].FragmentLength = Pkt->BlockOp[Index].Size;
447 }
448
449 //
450 // Set the fields of SndToken
451 //
452 SndToken->Packet.TxData = TxData;
453
454 //
455 // Set the fields of SndEntry
456 //
457 SndEntry->IpIo = IpIo;
458 SndEntry->Ip = Sender;
459 SndEntry->Context = Context;
460 SndEntry->NotifyData = NotifyData;
461
462 SndEntry->Pkt = Pkt;
463 NET_GET_REF (Pkt);
464
465 SndEntry->SndToken = SndToken;
466
467 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
468
469 return SndEntry;
470
471 ReleaseResource:
472 gBS->FreePool (TxData);
473
474 ReleaseEvent:
475 gBS->CloseEvent (SndToken->Event);
476
477 ReleaseSndToken:
478 gBS->FreePool (SndToken);
479
480 ReleaseSndEntry:
481 gBS->FreePool (SndEntry);
482
483 return NULL;
484 }
485
486
487 /**
488 Destroy the SndEntry.
489
490 This function pairs with IpIoCreateSndEntry().
491
492 @param SndEntry Pointer to the send entry to be destroyed.
493
494 **/
495 VOID
496 IpIoDestroySndEntry (
497 IN IP_IO_SEND_ENTRY *SndEntry
498 )
499 {
500 EFI_IP4_TRANSMIT_DATA *TxData;
501
502 TxData = SndEntry->SndToken->Packet.TxData;
503
504 if (NULL != TxData->OverrideData) {
505 gBS->FreePool (TxData->OverrideData);
506 }
507
508 gBS->FreePool (TxData);
509 NetbufFree (SndEntry->Pkt);
510 gBS->CloseEvent (SndEntry->SndToken->Event);
511
512 gBS->FreePool (SndEntry->SndToken);
513 RemoveEntryList (&SndEntry->Entry);
514
515 gBS->FreePool (SndEntry);
516 }
517
518
519 /**
520 Notify function for IP transmit token.
521
522 @param Context The context passed in by the event notifier.
523
524 **/
525 VOID
526 EFIAPI
527 IpIoTransmitHandlerDpc (
528 IN VOID *Context
529 )
530 {
531 IP_IO *IpIo;
532 IP_IO_SEND_ENTRY *SndEntry;
533
534 SndEntry = (IP_IO_SEND_ENTRY *) Context;
535
536 IpIo = SndEntry->IpIo;
537
538 if (IpIo->PktSentNotify && SndEntry->NotifyData) {
539 IpIo->PktSentNotify (
540 SndEntry->SndToken->Status,
541 SndEntry->Context,
542 SndEntry->Ip,
543 SndEntry->NotifyData
544 );
545 }
546
547 IpIoDestroySndEntry (SndEntry);
548 }
549
550 /**
551 Notify function for IP transmit token.
552
553 @param Event The event signaled.
554 @param Context The context passed in by the event notifier.
555
556 **/
557
558 VOID
559 EFIAPI
560 IpIoTransmitHandler (
561 IN EFI_EVENT Event,
562 IN VOID *Context
563 )
564 {
565 //
566 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
567 //
568 NetLibQueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
569 }
570
571
572 /**
573 The dummy handler for the dummy IP receive token.
574
575 @param Context The context passed in by the event notifier.
576
577 **/
578 VOID
579 EFIAPI
580 IpIoDummyHandlerDpc (
581 IN VOID *Context
582 )
583 {
584 IP_IO_IP_INFO *IpInfo;
585 EFI_IP4_COMPLETION_TOKEN *DummyToken;
586
587 IpInfo = (IP_IO_IP_INFO *) Context;
588 DummyToken = &(IpInfo->DummyRcvToken);
589
590 if (EFI_ABORTED == DummyToken->Status) {
591 //
592 // The reception is actively aborted by the consumer, directly return.
593 //
594 return;
595 } else if (EFI_SUCCESS == DummyToken->Status) {
596 ASSERT (DummyToken->Packet.RxData);
597
598 gBS->SignalEvent (DummyToken->Packet.RxData->RecycleSignal);
599 }
600
601 IpInfo->Ip->Receive (IpInfo->Ip, DummyToken);
602 }
603
604
605 /**
606 Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK.
607
608 @param Event The event signaled.
609 @param Context The context passed in by the event notifier.
610
611 **/
612 VOID
613 EFIAPI
614 IpIoDummyHandler (
615 IN EFI_EVENT Event,
616 IN VOID *Context
617 )
618 {
619 //
620 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
621 //
622 NetLibQueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
623 }
624
625
626 /**
627 Notify function for the IP receive token, used to process
628 the received IP packets.
629
630 @param Context The context passed in by the event notifier.
631
632 **/
633 VOID
634 EFIAPI
635 IpIoListenHandlerDpc (
636 IN VOID *Context
637 )
638 {
639 IP_IO *IpIo;
640 EFI_STATUS Status;
641 EFI_IP4_RECEIVE_DATA *RxData;
642 EFI_IP4_PROTOCOL *Ip;
643 EFI_NET_SESSION_DATA Session;
644 NET_BUF *Pkt;
645
646 IpIo = (IP_IO *) Context;
647
648 Ip = IpIo->Ip;
649 Status = IpIo->RcvToken.Status;
650 RxData = IpIo->RcvToken.Packet.RxData;
651
652 if (EFI_ABORTED == Status) {
653 //
654 // The reception is actively aborted by the consumer, directly return.
655 //
656 return;
657 }
658
659 if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {
660 //
661 // Only process the normal packets and the icmp error packets, if RxData is NULL
662 // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
663 // this should be a bug of the low layer (IP).
664 //
665 goto Resume;
666 }
667
668 if (NULL == IpIo->PktRcvdNotify) {
669 goto CleanUp;
670 }
671
672 if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&
673 !Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
674 //
675 // The source address is not zero and it's not a unicast IP address, discard it.
676 //
677 goto CleanUp;
678 }
679
680 //
681 // Create a netbuffer representing packet
682 //
683 Pkt = NetbufFromExt (
684 (NET_FRAGMENT *) RxData->FragmentTable,
685 RxData->FragmentCount,
686 0,
687 0,
688 IpIoExtFree,
689 RxData->RecycleSignal
690 );
691 if (NULL == Pkt) {
692 goto CleanUp;
693 }
694
695 //
696 // Create a net session
697 //
698 Session.Source = EFI_IP4 (RxData->Header->SourceAddress);
699 Session.Dest = EFI_IP4 (RxData->Header->DestinationAddress);
700 Session.IpHdr = RxData->Header;
701
702 if (EFI_SUCCESS == Status) {
703
704 IpIo->PktRcvdNotify (EFI_SUCCESS, (ICMP_ERROR) 0, &Session, Pkt, IpIo->RcvdContext);
705 } else {
706 //
707 // Status is EFI_ICMP_ERROR
708 //
709 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
710 if (EFI_ERROR (Status)) {
711 NetbufFree (Pkt);
712 }
713 }
714
715 goto Resume;
716
717 CleanUp:
718 gBS->SignalEvent (RxData->RecycleSignal);
719
720 Resume:
721 Ip->Receive (Ip, &(IpIo->RcvToken));
722 }
723
724
725 /**
726 Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
727
728 @param Event The event signaled.
729 @param Context The context passed in by the event notifier.
730
731 @return None.
732
733 **/
734 VOID
735 EFIAPI
736 IpIoListenHandler (
737 IN EFI_EVENT Event,
738 IN VOID *Context
739 )
740 {
741 //
742 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
743 //
744 NetLibQueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
745 }
746
747
748 /**
749 Create a new IP_IO instance.
750
751 This function uses IP4 service binding protocol in Controller to create an IP4
752 child (aka IP4 instance).
753
754 @param Image The image handle of the driver or application that
755 consumes IP_IO.
756 @param Controller The controller handle that has IP4 service binding
757 protocol installed.
758
759 @return Pointer to a newly created IP_IO instance, or NULL if failed.
760
761 **/
762 IP_IO *
763 EFIAPI
764 IpIoCreate (
765 IN EFI_HANDLE Image,
766 IN EFI_HANDLE Controller
767 )
768 {
769 EFI_STATUS Status;
770 IP_IO *IpIo;
771
772 IpIo = AllocateZeroPool (sizeof (IP_IO));
773 if (NULL == IpIo) {
774 return NULL;
775 }
776
777 InitializeListHead (&(IpIo->PendingSndList));
778 InitializeListHead (&(IpIo->IpList));
779 IpIo->Controller = Controller;
780 IpIo->Image = Image;
781
782 Status = gBS->CreateEvent (
783 EVT_NOTIFY_SIGNAL,
784 TPL_NOTIFY,
785 IpIoListenHandler,
786 IpIo,
787 &(IpIo->RcvToken.Event)
788 );
789 if (EFI_ERROR (Status)) {
790 goto ReleaseIpIo;
791 }
792
793 //
794 // Create an IP child and open IP protocol
795 //
796 Status = IpIoCreateIpChildOpenProtocol (
797 Controller,
798 Image,
799 &IpIo->ChildHandle,
800 (VOID **)&(IpIo->Ip)
801 );
802 if (EFI_ERROR (Status)) {
803 goto ReleaseIpIo;
804 }
805
806 return IpIo;
807
808 ReleaseIpIo:
809
810 if (NULL != IpIo->RcvToken.Event) {
811 gBS->CloseEvent (IpIo->RcvToken.Event);
812 }
813
814 gBS->FreePool (IpIo);
815
816 return NULL;
817 }
818
819
820 /**
821 Open an IP_IO instance for use.
822
823 This function is called after IpIoCreate(). It is used for configuring the IP
824 instance and register the callbacks and their context data for sending and
825 receiving IP packets.
826
827 @param IpIo Pointer to an IP_IO instance that needs to open.
828 @param OpenData The configuration data and callbacks for the IP_IO
829 instance.
830
831 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
832 successfully.
833 @retval Other Error condition occurred.
834
835 **/
836 EFI_STATUS
837 EFIAPI
838 IpIoOpen (
839 IN IP_IO *IpIo,
840 IN IP_IO_OPEN_DATA *OpenData
841 )
842 {
843 EFI_STATUS Status;
844 EFI_IP4_PROTOCOL *Ip;
845
846 if (IpIo->IsConfigured) {
847 return EFI_ACCESS_DENIED;
848 }
849
850 Ip = IpIo->Ip;
851
852 //
853 // configure ip
854 //
855 Status = Ip->Configure (Ip, &OpenData->IpConfigData);
856 if (EFI_ERROR (Status)) {
857 return Status;
858 }
859
860 //
861 // bugbug: to delete the default route entry in this Ip, if it is:
862 // (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
863 // its code
864 //
865 Status = Ip->Routes (Ip, TRUE, &mZeroIp4Addr, &mZeroIp4Addr, &mZeroIp4Addr);
866
867 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
868 return Status;
869 }
870
871 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
872 IpIo->PktSentNotify = OpenData->PktSentNotify;
873
874 IpIo->RcvdContext = OpenData->RcvdContext;
875 IpIo->SndContext = OpenData->SndContext;
876
877 IpIo->Protocol = OpenData->IpConfigData.DefaultProtocol;
878
879 //
880 // start to listen incoming packet
881 //
882 Status = Ip->Receive (Ip, &(IpIo->RcvToken));
883 if (EFI_ERROR (Status)) {
884 Ip->Configure (Ip, NULL);
885 goto ErrorExit;
886 }
887
888 IpIo->IsConfigured = TRUE;
889 InsertTailList (&mActiveIpIoList, &IpIo->Entry);
890
891 ErrorExit:
892
893 return Status;
894 }
895
896
897 /**
898 Stop an IP_IO instance.
899
900 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
901 the pending send/receive tokens will be canceled.
902
903 @param IpIo Pointer to the IP_IO instance that needs to stop.
904
905 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
906 @retval Other Error condition occurred.
907
908 **/
909 EFI_STATUS
910 EFIAPI
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 This function is paired with IpIoCreate(). The IP_IO will be closed first.
968 Resource will be freed afterwards. See IpIoClose().
969
970 @param IpIo Pointer to the IP_IO instance that needs to be
971 destroyed.
972
973 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
974 @retval Other Error condition occurred.
975
976 **/
977 EFI_STATUS
978 EFIAPI
979 IpIoDestroy (
980 IN IP_IO *IpIo
981 )
982 {
983 //
984 // Stop the IpIo.
985 //
986 IpIoStop (IpIo);
987
988 //
989 // Close the IP protocol and destroy the child.
990 //
991 IpIoCloseProtocolDestroyIpChild (IpIo->Controller, IpIo->Image, IpIo->ChildHandle);
992
993 gBS->FreePool (IpIo);
994
995 return EFI_SUCCESS;
996 }
997
998
999 /**
1000 Send out an IP packet.
1001
1002 This function is called after IpIoOpen(). The data to be sent are wrapped in
1003 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1004 overriden by Sender. Other sending configs, like source address and gateway
1005 address etc., are specified in OverrideData.
1006
1007 @param IpIo Pointer to an IP_IO instance used for sending IP
1008 packet.
1009 @param Pkt Pointer to the IP packet to be sent.
1010 @param Sender The IP protocol instance used for sending.
1011 @param Context Optional context data
1012 @param NotifyData Optional notify data
1013 @param Dest The destination IP address to send this packet to.
1014 @param OverrideData The data to override some configuration of the IP
1015 instance used for sending.
1016
1017 @retval EFI_SUCCESS The operation is completed successfully.
1018 @retval EFI_NOT_STARTED The IpIo is not configured.
1019 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1020
1021 **/
1022 EFI_STATUS
1023 EFIAPI
1024 IpIoSend (
1025 IN IP_IO *IpIo,
1026 IN NET_BUF *Pkt,
1027 IN IP_IO_IP_INFO *Sender OPTIONAL,
1028 IN VOID *Context OPTIONAL,
1029 IN VOID *NotifyData OPTIONAL,
1030 IN IP4_ADDR Dest,
1031 IN IP_IO_OVERRIDE *OverrideData OPTIONAL
1032 )
1033 {
1034 EFI_STATUS Status;
1035 EFI_IP4_PROTOCOL *Ip;
1036 IP_IO_SEND_ENTRY *SndEntry;
1037
1038 if (!IpIo->IsConfigured) {
1039 return EFI_NOT_STARTED;
1040 }
1041
1042 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
1043
1044 //
1045 // create a new SndEntry
1046 //
1047 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
1048 if (NULL == SndEntry) {
1049 return EFI_OUT_OF_RESOURCES;
1050 }
1051
1052 //
1053 // Send this Packet
1054 //
1055 Status = Ip->Transmit (Ip, SndEntry->SndToken);
1056 if (EFI_ERROR (Status)) {
1057 IpIoDestroySndEntry (SndEntry);
1058 }
1059
1060 return Status;
1061 }
1062
1063
1064 /**
1065 Cancel the IP transmit token which wraps this Packet.
1066
1067 @param IpIo Pointer to the IP_IO instance.
1068 @param Packet Pointer to the packet of NET_BUF to cancel.
1069
1070 **/
1071 VOID
1072 EFIAPI
1073 IpIoCancelTxToken (
1074 IN IP_IO *IpIo,
1075 IN VOID *Packet
1076 )
1077 {
1078 LIST_ENTRY *Node;
1079 IP_IO_SEND_ENTRY *SndEntry;
1080 EFI_IP4_PROTOCOL *Ip;
1081
1082 ASSERT (IpIo && Packet);
1083
1084 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
1085
1086 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
1087
1088 if (SndEntry->Pkt == Packet) {
1089
1090 Ip = SndEntry->Ip;
1091 Ip->Cancel (Ip, SndEntry->SndToken);
1092
1093 break;
1094 }
1095 }
1096
1097 }
1098
1099
1100 /**
1101 Add a new IP instance for sending data.
1102
1103 The function is used to add the IP_IO to the IP_IO sending list. The caller
1104 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1105 data.
1106
1107 @param IpIo Pointer to a IP_IO instance to add a new IP
1108 instance for sending purpose.
1109
1110 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1111
1112 **/
1113 IP_IO_IP_INFO *
1114 EFIAPI
1115 IpIoAddIp (
1116 IN IP_IO *IpIo
1117 )
1118 {
1119 EFI_STATUS Status;
1120 IP_IO_IP_INFO *IpInfo;
1121
1122 ASSERT (IpIo);
1123
1124 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
1125 if (IpInfo == NULL) {
1126 return IpInfo;
1127 }
1128
1129 //
1130 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1131 // instance.
1132 //
1133 InitializeListHead (&IpInfo->Entry);
1134 IpInfo->ChildHandle = NULL;
1135 IpInfo->Addr = 0;
1136 IpInfo->SubnetMask = 0;
1137 IpInfo->RefCnt = 1;
1138
1139 //
1140 // Create the IP instance and open the Ip4 protocol.
1141 //
1142 Status = IpIoCreateIpChildOpenProtocol (
1143 IpIo->Controller,
1144 IpIo->Image,
1145 &IpInfo->ChildHandle,
1146 (VOID **) &IpInfo->Ip
1147 );
1148 if (EFI_ERROR (Status)) {
1149 goto ReleaseIpInfo;
1150 }
1151
1152 //
1153 // Create the event for the DummyRcvToken.
1154 //
1155 Status = gBS->CreateEvent (
1156 EVT_NOTIFY_SIGNAL,
1157 TPL_NOTIFY,
1158 IpIoDummyHandler,
1159 IpInfo,
1160 &IpInfo->DummyRcvToken.Event
1161 );
1162 if (EFI_ERROR (Status)) {
1163 goto ReleaseIpChild;
1164 }
1165
1166 //
1167 // Link this IpInfo into the IpIo.
1168 //
1169 InsertTailList (&IpIo->IpList, &IpInfo->Entry);
1170
1171 return IpInfo;
1172
1173 ReleaseIpChild:
1174
1175 IpIoCloseProtocolDestroyIpChild (
1176 IpIo->Controller,
1177 IpIo->Image,
1178 IpInfo->ChildHandle
1179 );
1180
1181 ReleaseIpInfo:
1182
1183 gBS->FreePool (IpInfo);
1184
1185 return NULL;
1186 }
1187
1188
1189 /**
1190 Configure the IP instance of this IpInfo and start the receiving if Ip4ConfigData
1191 is not NULL.
1192
1193 @param IpInfo Pointer to the IP_IO_IP_INFO instance.
1194 @param Ip4ConfigData The IP4 configure data used to configure the IP
1195 instance, if NULL the IP instance is reset. If
1196 UseDefaultAddress is set to TRUE, and the configure
1197 operation succeeds, the default address information
1198 is written back in this Ip4ConfigData.
1199
1200 @retval EFI_STATUS The status returned by IP4->Configure or
1201 IP4->Receive.
1202 @retval Other Configuration fails.
1203
1204 **/
1205 EFI_STATUS
1206 EFIAPI
1207 IpIoConfigIp (
1208 IN IP_IO_IP_INFO *IpInfo,
1209 IN OUT EFI_IP4_CONFIG_DATA *Ip4ConfigData OPTIONAL
1210 )
1211 {
1212 EFI_STATUS Status;
1213 EFI_IP4_PROTOCOL *Ip;
1214 EFI_IP4_MODE_DATA Ip4ModeData;
1215
1216 ASSERT (IpInfo);
1217
1218 if (IpInfo->RefCnt > 1) {
1219 //
1220 // This IP instance is shared, don't reconfigure it until it has only one
1221 // consumer. Currently, only the tcp children cloned from their passive parent
1222 // will share the same IP. So this cases only happens while Ip4ConfigData is NULL,
1223 // let the last consumer clean the IP instance.
1224 //
1225 return EFI_SUCCESS;
1226 }
1227
1228 Ip = IpInfo->Ip;
1229
1230 Status = Ip->Configure (Ip, Ip4ConfigData);
1231 if (EFI_ERROR (Status)) {
1232 goto OnExit;
1233 }
1234
1235 if (Ip4ConfigData != NULL) {
1236
1237 if (Ip4ConfigData->UseDefaultAddress) {
1238 Ip->GetModeData (Ip, &Ip4ModeData, NULL, NULL);
1239
1240 Ip4ConfigData->StationAddress = Ip4ModeData.ConfigData.StationAddress;
1241 Ip4ConfigData->SubnetMask = Ip4ModeData.ConfigData.SubnetMask;
1242 }
1243
1244 CopyMem (&IpInfo->Addr, &Ip4ConfigData->StationAddress, sizeof (IP4_ADDR));
1245 CopyMem (&IpInfo->SubnetMask, &Ip4ConfigData->SubnetMask, sizeof (IP4_ADDR));
1246
1247 Status = Ip->Receive (Ip, &IpInfo->DummyRcvToken);
1248 if (EFI_ERROR (Status)) {
1249 Ip->Configure (Ip, NULL);
1250 }
1251 } else {
1252
1253 //
1254 // The IP instance is reseted, set the stored Addr and SubnetMask to zero.
1255 //
1256 IpInfo->Addr = 0;
1257 IpInfo->SubnetMask =0;
1258 }
1259
1260 OnExit:
1261
1262 return Status;
1263 }
1264
1265
1266 /**
1267 Destroy an IP instance maintained in IpIo->IpList for
1268 sending purpose.
1269
1270 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1271 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1272 will be dstroyed if the RefCnt is zero.
1273
1274 @param IpIo Pointer to the IP_IO instance.
1275 @param IpInfo Pointer to the IpInfo to be removed.
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 This function is called when the caller needs the IpIo to send data to the
1311 specified Src. The IpIo was added previously by IpIoAddIp().
1312
1313 @param IpIo Pointer to the pointer of the IP_IO instance.
1314 @param Src The local IP address.
1315
1316 @return Pointer to the IP protocol can be used for sending purpose and its local
1317 address is the same with Src.
1318
1319 **/
1320 IP_IO_IP_INFO *
1321 EFIAPI
1322 IpIoFindSender (
1323 IN OUT IP_IO **IpIo,
1324 IN IP4_ADDR Src
1325 )
1326 {
1327 LIST_ENTRY *IpIoEntry;
1328 IP_IO *IpIoPtr;
1329 LIST_ENTRY *IpInfoEntry;
1330 IP_IO_IP_INFO *IpInfo;
1331
1332 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
1333 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
1334
1335 if ((*IpIo != NULL) && (*IpIo != IpIoPtr)) {
1336 continue;
1337 }
1338
1339 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
1340 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
1341
1342 if (IpInfo->Addr == Src) {
1343 *IpIo = IpIoPtr;
1344 return IpInfo;
1345 }
1346 }
1347 }
1348
1349 //
1350 // No match.
1351 //
1352 return NULL;
1353 }
1354
1355
1356 /**
1357 Get the ICMP error map information.
1358
1359 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
1360 are not NULL, this routine will fill them.
1361
1362 @param IcmpError IcmpError Type
1363 @param IsHard Whether it is a hard error
1364 @param Notify Whether it need to notify SockError
1365
1366 @return ICMP Error Status
1367
1368 **/
1369 EFI_STATUS
1370 EFIAPI
1371 IpIoGetIcmpErrStatus (
1372 IN ICMP_ERROR IcmpError,
1373 OUT BOOLEAN *IsHard OPTIONAL,
1374 OUT BOOLEAN *Notify OPTIONAL
1375 )
1376 {
1377 ASSERT ((IcmpError >= ICMP_ERR_UNREACH_NET) && (IcmpError <= ICMP_ERR_PARAMPROB));
1378
1379 if (IsHard != NULL) {
1380 *IsHard = mIcmpErrMap[IcmpError].IsHard;
1381 }
1382
1383 if (Notify != NULL) {
1384 *Notify = mIcmpErrMap[IcmpError].Notify;
1385 }
1386
1387 switch (IcmpError) {
1388 case ICMP_ERR_UNREACH_NET:
1389 return EFI_NETWORK_UNREACHABLE;
1390
1391 case ICMP_ERR_TIMXCEED_INTRANS:
1392 case ICMP_ERR_TIMXCEED_REASS:
1393 case ICMP_ERR_UNREACH_HOST:
1394 return EFI_HOST_UNREACHABLE;
1395
1396 case ICMP_ERR_UNREACH_PROTOCOL:
1397 return EFI_PROTOCOL_UNREACHABLE;
1398
1399 case ICMP_ERR_UNREACH_PORT:
1400 return EFI_PORT_UNREACHABLE;
1401
1402 case ICMP_ERR_MSGSIZE:
1403 case ICMP_ERR_UNREACH_SRCFAIL:
1404 case ICMP_ERR_QUENCH:
1405 case ICMP_ERR_PARAMPROB:
1406 return EFI_ICMP_ERROR;
1407 }
1408
1409 //
1410 // will never run here!
1411 //
1412 ASSERT (FALSE);
1413 return EFI_UNSUPPORTED;
1414 }
1415