Changed the code style. it could pass EBC and ICC build.
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
CommitLineData
cbf316f2 1/** @file\r
2\r
3Copyright (c) 2005 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 IpIo.c\r
15\r
16Abstract:\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
b61439a7 32#include <Library/BaseMemoryLib.h>\r
cbf316f2 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
39NET_LIST_ENTRY mActiveIpIoList = {\r
40 &mActiveIpIoList,\r
41 &mActiveIpIoList\r
42};\r
43\r
44EFI_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
84b5c78e 51 {{0, 0, 0, 0}},\r
52 {{0, 0, 0, 0}},\r
cbf316f2 53 0,\r
54 255,\r
55 FALSE,\r
56 FALSE,\r
57 0,\r
58 0\r
59};\r
60\r
01750eb0 61STATIC 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
cbf316f2 74STATIC\r
75VOID\r
76EFIAPI\r
77IpIoTransmitHandler (\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
97STATIC\r
98EFI_STATUS\r
99IpIoCreateIpChildOpenProtocol (\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
160STATIC\r
161EFI_STATUS\r
162IpIoCloseProtocolDestroyIpChild (\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
205STATIC\r
206EFI_STATUS\r
207IpIoIcmpHandler (\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
4eb65aff 246 IcmpErr = (ICMP_ERROR) (ICMP_ERR_UNREACH_NET + Code);\r
cbf316f2 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
4eb65aff 283 IcmpErr = (ICMP_ERROR) (Code + ICMP_ERR_TIMXCEED_INTRANS);\r
cbf316f2 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
337STATIC\r
338VOID\r
339IpIoExtFree (\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
362STATIC\r
363IP_IO_SEND_ENTRY *\r
364IpIoCreateSndEntry (\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
34edf2ae 379 volatile UINT32 Index;\r
cbf316f2 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
b61439a7 433 NetCopyMem (OverrideData, Override, sizeof (*OverrideData));\r
cbf316f2 434 }\r
435\r
436 //\r
437 // Set the fields of TxData\r
438 //\r
b61439a7 439 NetCopyMem (&TxData->DestinationAddress, &Dest, sizeof (EFI_IPv4_ADDRESS));\r
cbf316f2 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
cbf316f2 446\r
34edf2ae 447 for (Index = 0; Index < Pkt->BlockOpNum; Index++) {\r
cbf316f2 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
474ReleaseResource:\r
475 NetFreePool (TxData);\r
476\r
477ReleaseEvent:\r
478 gBS->CloseEvent (SndToken->Event);\r
479\r
480ReleaseSndToken:\r
481 NetFreePool (SndToken);\r
482\r
483ReleaseSndEntry:\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
498STATIC\r
499VOID\r
500IpIoDestroySndEntry (\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
532STATIC\r
533VOID\r
534EFIAPI\r
535IpIoTransmitHandler (\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
569STATIC\r
570VOID\r
571EFIAPI\r
572IpIoDummyHandler (\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
605STATIC\r
606VOID\r
607EFIAPI\r
608IpIoListenHandler (\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
4eb65aff 671 IpIo->PktRcvdNotify (EFI_SUCCESS, (ICMP_ERROR) 0, &Session, Pkt, IpIo->RcvdContext);\r
cbf316f2 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
684CleanUp:\r
685 gBS->SignalEvent (RxData->RecycleSignal);\r
686\r
687Resume:\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
702IP_IO *\r
703IpIoCreate (\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
747ReleaseIpIo:\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
770EFI_STATUS\r
771IpIoOpen (\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
cbf316f2 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
b61439a7 798 Status = Ip->Routes (Ip, TRUE, &mZeroIp4Addr, &mZeroIp4Addr, &mZeroIp4Addr);\r
cbf316f2 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
824ErrorExit:\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
839EFI_STATUS\r
840IpIoStop (\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
34edf2ae 872\r
cbf316f2 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
903EFI_STATUS\r
904IpIoDestroy (\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
941EFI_STATUS\r
942IpIoSend (\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
991VOID\r
992IpIoCancelTxToken (\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
1034IP_IO_IP_INFO *\r
1035IpIoAddIp (\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
4eb65aff 1066 (VOID **) &IpInfo->Ip\r
cbf316f2 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
1093ReleaseIpChild:\r
1094\r
1095 IpIoCloseProtocolDestroyIpChild (\r
1096 IpIo->Controller,\r
1097 IpIo->Image,\r
1098 IpInfo->ChildHandle\r
1099 );\r
1100\r
1101ReleaseIpInfo:\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
1124EFI_STATUS\r
1125IpIoConfigIp (\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
b61439a7 1162 NetCopyMem (&IpInfo->Addr, &Ip4ConfigData->StationAddress, sizeof (IP4_ADDR));\r
1163 NetCopyMem (&IpInfo->SubnetMask, &Ip4ConfigData->SubnetMask, sizeof (IP4_ADDR));\r
cbf316f2 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
1178OnExit:\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
1194VOID\r
1195IpIoRemoveIp (\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
1232IP_IO_IP_INFO *\r
1233IpIoFindSender (\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
1280EFI_STATUS\r
1281IpIoGetIcmpErrStatus (\r
1282 IN ICMP_ERROR IcmpError,\r
1283 OUT BOOLEAN *IsHard, OPTIONAL\r
1284 OUT BOOLEAN *Notify OPTIONAL\r
1285 )\r
1286{\r
01750eb0 1287 ASSERT ((IcmpError >= ICMP_ERR_UNREACH_NET) && (IcmpError <= ICMP_ERR_PARAMPROB));\r
687a2e5f 1288\r
01750eb0 1289 if (IsHard != NULL) {\r
1290 *IsHard = mIcmpErrMap[IcmpError].IsHard;\r
1291 }\r
687a2e5f 1292\r
01750eb0 1293 if (Notify != NULL) {\r
1294 *Notify = mIcmpErrMap[IcmpError].Notify;\r
1295 }\r
687a2e5f 1296\r
01750eb0 1297 switch (IcmpError) {\r
1298 case ICMP_ERR_UNREACH_NET:\r
1299 return EFI_NETWORK_UNREACHABLE;\r
687a2e5f 1300\r
01750eb0 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
cbf316f2 1305\r
01750eb0 1306 case ICMP_ERR_UNREACH_PROTOCOL:\r
1307 return EFI_PROTOCOL_UNREACHABLE;\r
cbf316f2 1308\r
01750eb0 1309 case ICMP_ERR_UNREACH_PORT:\r
1310 return EFI_PORT_UNREACHABLE;\r
cbf316f2 1311\r
01750eb0 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
cbf316f2 1317 }\r
1318\r
01750eb0 1319 //\r
1320 // will never run here!\r
1321 //\r
1322 ASSERT (FALSE);\r
1323 return EFI_UNSUPPORTED;\r
cbf316f2 1324}\r
1325\r