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