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