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