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