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