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