]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
Add includes for definitions used by the DxeIpIoLib and DxeNetLib
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
1 /** @file
2 IpIo Library.
3
4 Copyright (c) 2005 - 2007, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13
14 #include <Uefi.h>
15
16 #include <Protocol/Udp4.h>
17
18 #include <Library/IpIoLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/MemoryAllocationLib.h>
24
25
26 LIST_ENTRY mActiveIpIoList = {
27 &mActiveIpIoList,
28 &mActiveIpIoList
29 };
30
31 EFI_IP4_CONFIG_DATA mIpIoDefaultIpConfigData = {
32 EFI_IP_PROTO_UDP,
33 FALSE,
34 TRUE,
35 FALSE,
36 FALSE,
37 FALSE,
38 {{0, 0, 0, 0}},
39 {{0, 0, 0, 0}},
40 0,
41 255,
42 FALSE,
43 FALSE,
44 0,
45 0
46 };
47
48 ICMP_ERROR_INFO mIcmpErrMap[10] = {
49 {FALSE, TRUE},
50 {FALSE, TRUE},
51 {TRUE, TRUE},
52 {TRUE, TRUE},
53 {TRUE, TRUE},
54 {FALSE, TRUE},
55 {FALSE, TRUE},
56 {FALSE, TRUE},
57 {FALSE, FALSE},
58 {FALSE, TRUE}
59 };
60
61
62 /**
63 Notify function for IP transmit token.
64
65 @param[in] Context The context passed in by the event notifier.
66
67 **/
68 VOID
69 EFIAPI
70 IpIoTransmitHandlerDpc (
71 IN VOID *Context
72 );
73
74
75 /**
76 Notify function for IP transmit token.
77
78 @param[in] Event The event signaled.
79 @param[in] Context The context passed in by the event notifier.
80
81 **/
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, and return the opened
92 IP protocol as Interface.
93
94 @param[in] ControllerHandle The controller handle.
95 @param[in] ImageHandle The image handle.
96 @param[in] ChildHandle Pointer to the buffer to save the IP child handle.
97 @param[out] 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 Others The required operation failed.
102
103 **/
104 EFI_STATUS
105 IpIoCreateIpChildOpenProtocol (
106 IN EFI_HANDLE ControllerHandle,
107 IN EFI_HANDLE ImageHandle,
108 IN EFI_HANDLE *ChildHandle,
109 OUT VOID **Interface
110 )
111 {
112 EFI_STATUS Status;
113
114 //
115 // Create an IP child.
116 //
117 Status = NetLibCreateServiceChild (
118 ControllerHandle,
119 ImageHandle,
120 &gEfiIp4ServiceBindingProtocolGuid,
121 ChildHandle
122 );
123 if (EFI_ERROR (Status)) {
124 return Status;
125 }
126
127 //
128 // Open the IP protocol installed on the *ChildHandle.
129 //
130 Status = gBS->OpenProtocol (
131 *ChildHandle,
132 &gEfiIp4ProtocolGuid,
133 Interface,
134 ImageHandle,
135 ControllerHandle,
136 EFI_OPEN_PROTOCOL_BY_DRIVER
137 );
138 if (EFI_ERROR (Status)) {
139 //
140 // On failure, destroy the IP child.
141 //
142 NetLibDestroyServiceChild (
143 ControllerHandle,
144 ImageHandle,
145 &gEfiIp4ServiceBindingProtocolGuid,
146 *ChildHandle
147 );
148 }
149
150 return Status;
151 }
152
153
154 /**
155 This function close the previously openned IP protocol and destroy the IP child.
156
157 @param[in] ControllerHandle The controller handle.
158 @param[in] ImageHandle The image handle.
159 @param[in] ChildHandle The child handle of the IP child.
160
161 @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child
162 is destroyed.
163 @retval Others The required operation failed.
164
165 **/
166 EFI_STATUS
167 IpIoCloseProtocolDestroyIpChild (
168 IN EFI_HANDLE ControllerHandle,
169 IN EFI_HANDLE ImageHandle,
170 IN EFI_HANDLE ChildHandle
171 )
172 {
173 EFI_STATUS Status;
174
175 //
176 // Close the previously openned IP protocol.
177 //
178 gBS->CloseProtocol (
179 ChildHandle,
180 &gEfiIp4ProtocolGuid,
181 ImageHandle,
182 ControllerHandle
183 );
184
185 //
186 // Destroy the IP child.
187 //
188 Status = NetLibDestroyServiceChild (
189 ControllerHandle,
190 ImageHandle,
191 &gEfiIp4ServiceBindingProtocolGuid,
192 ChildHandle
193 );
194
195 return Status;
196 }
197
198
199 /**
200 This function handles ICMP packets.
201
202 @param[in] IpIo Pointer to the IP_IO instance.
203 @param[in, out] Pkt Pointer to the ICMP packet.
204 @param[in] Session Pointer to the net session of this ICMP packet.
205
206 @retval EFI_SUCCESS The ICMP packet is handled successfully.
207 @retval EFI_ABORTED This type of ICMP packet is not supported.
208
209 **/
210 EFI_STATUS
211 IpIoIcmpHandler (
212 IN IP_IO *IpIo,
213 IN OUT NET_BUF *Pkt,
214 IN EFI_NET_SESSION_DATA *Session
215 )
216 {
217 IP4_ICMP_ERROR_HEAD *IcmpHdr;
218 EFI_IP4_HEADER *IpHdr;
219 ICMP_ERROR IcmpErr;
220 UINT8 *PayLoadHdr;
221 UINT8 Type;
222 UINT8 Code;
223 UINT32 TrimBytes;
224
225 IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);
226 IpHdr = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);
227
228 //
229 // Check the ICMP packet length.
230 //
231 if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {
232
233 return EFI_ABORTED;
234 }
235
236 Type = IcmpHdr->Head.Type;
237 Code = IcmpHdr->Head.Code;
238
239 //
240 // Analyze the ICMP Error in this ICMP pkt
241 //
242 switch (Type) {
243 case ICMP_TYPE_UNREACH:
244 switch (Code) {
245 case ICMP_CODE_UNREACH_NET:
246 case ICMP_CODE_UNREACH_HOST:
247 case ICMP_CODE_UNREACH_PROTOCOL:
248 case ICMP_CODE_UNREACH_PORT:
249 case ICMP_CODE_UNREACH_SRCFAIL:
250 IcmpErr = (ICMP_ERROR) (ICMP_ERR_UNREACH_NET + Code);
251
252 break;
253
254 case ICMP_CODE_UNREACH_NEEDFRAG:
255 IcmpErr = ICMP_ERR_MSGSIZE;
256
257 break;
258
259 case ICMP_CODE_UNREACH_NET_UNKNOWN:
260 case ICMP_CODE_UNREACH_NET_PROHIB:
261 case ICMP_CODE_UNREACH_TOSNET:
262 IcmpErr = ICMP_ERR_UNREACH_NET;
263
264 break;
265
266 case ICMP_CODE_UNREACH_HOST_UNKNOWN:
267 case ICMP_CODE_UNREACH_ISOLATED:
268 case ICMP_CODE_UNREACH_HOST_PROHIB:
269 case ICMP_CODE_UNREACH_TOSHOST:
270 IcmpErr = ICMP_ERR_UNREACH_HOST;
271
272 break;
273
274 default:
275 return EFI_ABORTED;
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
311 //
312 // Notify user the ICMP pkt only containing payload except
313 // IP and ICMP header
314 //
315 PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));
316 TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
317
318 NetbufTrim (Pkt, TrimBytes, TRUE);
319
320 IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
321
322 return EFI_SUCCESS;
323 }
324
325
326 /**
327 Free function for receive token of IP_IO. It is used to
328 signal the recycle event to notify IP to recycle the
329 data buffer.
330
331 @param[in] Event The event to be signaled.
332
333 **/
334 VOID
335 IpIoExtFree (
336 IN VOID *Event
337 )
338 {
339 gBS->SignalEvent ((EFI_EVENT) Event);
340 }
341
342
343 /**
344 Create a send entry to wrap a packet before sending
345 out it through IP.
346
347 @param[in, out] IpIo Pointer to the IP_IO instance.
348 @param[in, out] Pkt Pointer to the packet.
349 @param[in] Sender Pointer to the IP sender.
350 @param[in] Context Pointer to the context.
351 @param[in] NotifyData Pointer to the notify data.
352 @param[in] Dest Pointer to the destination IP address.
353 @param[in] Override Pointer to the overriden IP_IO data.
354
355 @return Pointer to the data structure created to wrap the packet. If NULL,
356 @return resource limit occurred.
357
358 **/
359 IP_IO_SEND_ENTRY *
360 IpIoCreateSndEntry (
361 IN OUT IP_IO *IpIo,
362 IN OUT NET_BUF *Pkt,
363 IN EFI_IP4_PROTOCOL *Sender,
364 IN VOID *Context OPTIONAL,
365 IN VOID *NotifyData OPTIONAL,
366 IN IP4_ADDR Dest,
367 IN IP_IO_OVERRIDE *Override
368 )
369 {
370 IP_IO_SEND_ENTRY *SndEntry;
371 EFI_IP4_COMPLETION_TOKEN *SndToken;
372 EFI_IP4_TRANSMIT_DATA *TxData;
373 EFI_STATUS Status;
374 EFI_IP4_OVERRIDE_DATA *OverrideData;
375 volatile UINT32 Index;
376
377 //
378 // Allocate resource for SndEntry
379 //
380 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
381 if (NULL == SndEntry) {
382 return NULL;
383 }
384
385 //
386 // Allocate resource for SndToken
387 //
388 SndToken = AllocatePool (sizeof (EFI_IP4_COMPLETION_TOKEN));
389 if (NULL == SndToken) {
390 goto ReleaseSndEntry;
391 }
392
393 Status = gBS->CreateEvent (
394 EVT_NOTIFY_SIGNAL,
395 TPL_NOTIFY,
396 IpIoTransmitHandler,
397 SndEntry,
398 &(SndToken->Event)
399 );
400 if (EFI_ERROR (Status)) {
401 goto ReleaseSndToken;
402 }
403
404 //
405 // Allocate resource for TxData
406 //
407 TxData = AllocatePool (
408 sizeof (EFI_IP4_TRANSMIT_DATA) +
409 sizeof (EFI_IP4_FRAGMENT_DATA) * (Pkt->BlockOpNum - 1)
410 );
411
412 if (NULL == TxData) {
413 goto ReleaseEvent;
414 }
415
416 //
417 // Allocate resource for OverrideData if needed
418 //
419 OverrideData = NULL;
420 if (NULL != Override) {
421
422 OverrideData = AllocatePool (sizeof (EFI_IP4_OVERRIDE_DATA));
423 if (NULL == OverrideData) {
424 goto ReleaseResource;
425 }
426 //
427 // Set the fields of OverrideData
428 //
429 CopyMem (OverrideData, Override, sizeof (*OverrideData));
430 }
431
432 //
433 // Set the fields of TxData
434 //
435 CopyMem (&TxData->DestinationAddress, &Dest, sizeof (EFI_IPv4_ADDRESS));
436 TxData->OverrideData = OverrideData;
437 TxData->OptionsLength = 0;
438 TxData->OptionsBuffer = NULL;
439 TxData->TotalDataLength = Pkt->TotalSize;
440 TxData->FragmentCount = Pkt->BlockOpNum;
441
442
443 for (Index = 0; Index < Pkt->BlockOpNum; Index++) {
444 TxData->FragmentTable[Index].FragmentBuffer = Pkt->BlockOp[Index].Head;
445 TxData->FragmentTable[Index].FragmentLength = Pkt->BlockOp[Index].Size;
446 }
447
448 //
449 // Set the fields of SndToken
450 //
451 SndToken->Packet.TxData = TxData;
452
453 //
454 // Set the fields of SndEntry
455 //
456 SndEntry->IpIo = IpIo;
457 SndEntry->Ip = Sender;
458 SndEntry->Context = Context;
459 SndEntry->NotifyData = NotifyData;
460
461 SndEntry->Pkt = Pkt;
462 NET_GET_REF (Pkt);
463
464 SndEntry->SndToken = SndToken;
465
466 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
467
468 return SndEntry;
469
470 ReleaseResource:
471 gBS->FreePool (TxData);
472
473 ReleaseEvent:
474 gBS->CloseEvent (SndToken->Event);
475
476 ReleaseSndToken:
477 gBS->FreePool (SndToken);
478
479 ReleaseSndEntry:
480 gBS->FreePool (SndEntry);
481
482 return NULL;
483 }
484
485
486 /**
487 Destroy the SndEntry.
488
489 This function pairs with IpIoCreateSndEntry().
490
491 @param[in] SndEntry Pointer to the send entry to be destroyed.
492
493 **/
494 VOID
495 IpIoDestroySndEntry (
496 IN IP_IO_SEND_ENTRY *SndEntry
497 )
498 {
499 EFI_IP4_TRANSMIT_DATA *TxData;
500
501 TxData = SndEntry->SndToken->Packet.TxData;
502
503 if (NULL != TxData->OverrideData) {
504 gBS->FreePool (TxData->OverrideData);
505 }
506
507 gBS->FreePool (TxData);
508 NetbufFree (SndEntry->Pkt);
509 gBS->CloseEvent (SndEntry->SndToken->Event);
510
511 gBS->FreePool (SndEntry->SndToken);
512 RemoveEntryList (&SndEntry->Entry);
513
514 gBS->FreePool (SndEntry);
515 }
516
517
518 /**
519 Notify function for IP transmit token.
520
521 @param[in] Context The context passed in by the event notifier.
522
523 **/
524 VOID
525 EFIAPI
526 IpIoTransmitHandlerDpc (
527 IN VOID *Context
528 )
529 {
530 IP_IO *IpIo;
531 IP_IO_SEND_ENTRY *SndEntry;
532
533 SndEntry = (IP_IO_SEND_ENTRY *) Context;
534
535 IpIo = SndEntry->IpIo;
536
537 if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {
538 IpIo->PktSentNotify (
539 SndEntry->SndToken->Status,
540 SndEntry->Context,
541 SndEntry->Ip,
542 SndEntry->NotifyData
543 );
544 }
545
546 IpIoDestroySndEntry (SndEntry);
547 }
548
549
550 /**
551 Notify function for IP transmit token.
552
553 @param[in] Event The event signaled.
554 @param[in] Context The context passed in by the event notifier.
555
556 **/
557 VOID
558 EFIAPI
559 IpIoTransmitHandler (
560 IN EFI_EVENT Event,
561 IN VOID *Context
562 )
563 {
564 //
565 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
566 //
567 NetLibQueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
568 }
569
570
571 /**
572 The dummy handler for the dummy IP receive token.
573
574 @param[in] Context The context passed in by the event notifier.
575
576 **/
577 VOID
578 EFIAPI
579 IpIoDummyHandlerDpc (
580 IN VOID *Context
581 )
582 {
583 IP_IO_IP_INFO *IpInfo;
584 EFI_IP4_COMPLETION_TOKEN *DummyToken;
585
586 IpInfo = (IP_IO_IP_INFO *) Context;
587 DummyToken = &(IpInfo->DummyRcvToken);
588
589 if (EFI_ABORTED == DummyToken->Status) {
590 //
591 // The reception is actively aborted by the consumer, directly return.
592 //
593 return;
594 } else if (EFI_SUCCESS == DummyToken->Status) {
595 ASSERT ((DummyToken->Packet.RxData)!= NULL);
596
597 gBS->SignalEvent (DummyToken->Packet.RxData->RecycleSignal);
598 }
599
600 IpInfo->Ip->Receive (IpInfo->Ip, DummyToken);
601 }
602
603
604 /**
605 This function add IpIoDummyHandlerDpc to the end of the DPC queue.
606
607 @param[in] Event The event signaled.
608 @param[in] Context The context passed in by the event notifier.
609
610 **/
611 VOID
612 EFIAPI
613 IpIoDummyHandler (
614 IN EFI_EVENT Event,
615 IN VOID *Context
616 )
617 {
618 //
619 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
620 //
621 NetLibQueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
622 }
623
624
625 /**
626 Notify function for the IP receive token, used to process
627 the received IP packets.
628
629 @param[in] Context The context passed in by the event notifier.
630
631 **/
632 VOID
633 EFIAPI
634 IpIoListenHandlerDpc (
635 IN VOID *Context
636 )
637 {
638 IP_IO *IpIo;
639 EFI_STATUS Status;
640 EFI_IP4_RECEIVE_DATA *RxData;
641 EFI_IP4_PROTOCOL *Ip;
642 EFI_NET_SESSION_DATA Session;
643 NET_BUF *Pkt;
644
645 IpIo = (IP_IO *) Context;
646
647 Ip = IpIo->Ip;
648 Status = IpIo->RcvToken.Status;
649 RxData = IpIo->RcvToken.Packet.RxData;
650
651 if (EFI_ABORTED == Status) {
652 //
653 // The reception is actively aborted by the consumer, directly return.
654 //
655 return;
656 }
657
658 if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {
659 //
660 // @bug Only process the normal packets and the icmp error packets, if RxData is NULL
661 // @bug with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
662 // @bug this should be a bug of the low layer (IP).
663 //
664 goto Resume;
665 }
666
667 if (NULL == IpIo->PktRcvdNotify) {
668 goto CleanUp;
669 }
670
671 if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&
672 !Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
673 //
674 // The source address is not zero and it's not a unicast IP address, discard it.
675 //
676 goto CleanUp;
677 }
678
679 //
680 // Create a netbuffer representing packet
681 //
682 Pkt = NetbufFromExt (
683 (NET_FRAGMENT *) RxData->FragmentTable,
684 RxData->FragmentCount,
685 0,
686 0,
687 IpIoExtFree,
688 RxData->RecycleSignal
689 );
690 if (NULL == Pkt) {
691 goto CleanUp;
692 }
693
694 //
695 // Create a net session
696 //
697 Session.Source = EFI_IP4 (RxData->Header->SourceAddress);
698 Session.Dest = EFI_IP4 (RxData->Header->DestinationAddress);
699 Session.IpHdr = RxData->Header;
700
701 if (EFI_SUCCESS == Status) {
702
703 IpIo->PktRcvdNotify (EFI_SUCCESS, (ICMP_ERROR) 0, &Session, Pkt, IpIo->RcvdContext);
704 } else {
705 //
706 // Status is EFI_ICMP_ERROR
707 //
708 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
709 if (EFI_ERROR (Status)) {
710 NetbufFree (Pkt);
711 }
712 }
713
714 goto Resume;
715
716 CleanUp:
717 gBS->SignalEvent (RxData->RecycleSignal);
718
719 Resume:
720 Ip->Receive (Ip, &(IpIo->RcvToken));
721 }
722
723
724 /**
725 This function add IpIoListenHandlerDpc to the end of the DPC queue.
726
727 @param[in] Event The event signaled.
728 @param[in] Context The context passed in by the event notifier.
729
730 **/
731 VOID
732 EFIAPI
733 IpIoListenHandler (
734 IN EFI_EVENT Event,
735 IN VOID *Context
736 )
737 {
738 //
739 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
740 //
741 NetLibQueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
742 }
743
744
745 /**
746 Create a new IP_IO instance.
747
748 This function uses IP4 service binding protocol in Controller to create an IP4
749 child (aka IP4 instance).
750
751 @param[in] Image The image handle of the driver or application that
752 consumes IP_IO.
753 @param[in] Controller The controller handle that has IP4 service binding
754 protocol installed.
755
756 @return Pointer to a newly created IP_IO instance, or NULL if failed.
757
758 **/
759 IP_IO *
760 EFIAPI
761 IpIoCreate (
762 IN EFI_HANDLE Image,
763 IN EFI_HANDLE Controller
764 )
765 {
766 EFI_STATUS Status;
767 IP_IO *IpIo;
768
769 IpIo = AllocateZeroPool (sizeof (IP_IO));
770 if (NULL == IpIo) {
771 return NULL;
772 }
773
774 InitializeListHead (&(IpIo->PendingSndList));
775 InitializeListHead (&(IpIo->IpList));
776 IpIo->Controller = Controller;
777 IpIo->Image = Image;
778
779 Status = gBS->CreateEvent (
780 EVT_NOTIFY_SIGNAL,
781 TPL_NOTIFY,
782 IpIoListenHandler,
783 IpIo,
784 &(IpIo->RcvToken.Event)
785 );
786 if (EFI_ERROR (Status)) {
787 goto ReleaseIpIo;
788 }
789
790 //
791 // Create an IP child and open IP protocol
792 //
793 Status = IpIoCreateIpChildOpenProtocol (
794 Controller,
795 Image,
796 &IpIo->ChildHandle,
797 (VOID **)&(IpIo->Ip)
798 );
799 if (EFI_ERROR (Status)) {
800 goto ReleaseIpIo;
801 }
802
803 return IpIo;
804
805 ReleaseIpIo:
806
807 if (NULL != IpIo->RcvToken.Event) {
808 gBS->CloseEvent (IpIo->RcvToken.Event);
809 }
810
811 gBS->FreePool (IpIo);
812
813 return NULL;
814 }
815
816
817 /**
818 Open an IP_IO instance for use.
819
820 This function is called after IpIoCreate(). It is used for configuring the IP
821 instance and register the callbacks and their context data for sending and
822 receiving IP packets.
823
824 @param[in, out] IpIo Pointer to an IP_IO instance that needs
825 to open.
826 @param[in] OpenData The configuration data and callbacks for
827 the IP_IO instance.
828
829 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
830 successfully.
831 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
832 reopen it.
833 @retval Others Error condition occurred.
834
835 **/
836 EFI_STATUS
837 EFIAPI
838 IpIoOpen (
839 IN OUT 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 // @bug To delete the default route entry in this Ip, if it is:
862 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
863 // @bug 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[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
904
905 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
906 @retval Others Error condition occurred.
907
908 **/
909 EFI_STATUS
910 EFIAPI
911 IpIoStop (
912 IN OUT 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 send 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 IpIoCloseProtocolDestroyIpChild().
969
970 @param[in, out] 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 Others Error condition occurred.
975
976 **/
977 EFI_STATUS
978 EFIAPI
979 IpIoDestroy (
980 IN OUT 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[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1008 packet.
1009 @param[in, out] Pkt Pointer to the IP packet to be sent.
1010 @param[in] Sender The IP protocol instance used for sending.
1011 @param[in] Context Optional context data.
1012 @param[in] NotifyData Optional notify data.
1013 @param[in] Dest The destination IP address to send this packet to.
1014 @param[in] 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 OUT IP_IO *IpIo,
1026 IN OUT 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[in] IpIo Pointer to the IP_IO instance.
1068 @param[in] 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)!= NULL && (Packet)!= NULL);
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[in, out] 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 OUT IP_IO *IpIo
1117 )
1118 {
1119 EFI_STATUS Status;
1120 IP_IO_IP_INFO *IpInfo;
1121
1122 ASSERT (IpIo != NULL);
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[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1194 @param[in, out] 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_SUCCESS The IP instance of this IpInfo is configured successfully
1201 or no need to reconfigure it.
1202 @retval Others Configuration fails.
1203
1204 **/
1205 EFI_STATUS
1206 EFIAPI
1207 IpIoConfigIp (
1208 IN OUT 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 != NULL);
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[in] IpIo Pointer to the IP_IO instance.
1275 @param[in] 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[in, out] IpIo Pointer to the pointer of the IP_IO instance.
1314 @param[in] Src The local IP address.
1315
1316 @return Pointer to the IP protocol can be used for sending purpose and its local
1317 @return 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[in] IcmpError IcmpError Type.
1363 @param[out] IsHard Whether it is a hard error.
1364 @param[out] Notify Whether it need to notify SockError.
1365
1366 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
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