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