]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
... / ...
CommitLineData
1/** @file\r
2 IpIo Library.\r
3\r
4(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
5Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7**/\r
8\r
9#include <Uefi.h>\r
10\r
11#include <Protocol/Udp4.h>\r
12\r
13#include <Library/IpIoLib.h>\r
14#include <Library/BaseLib.h>\r
15#include <Library/DebugLib.h>\r
16#include <Library/BaseMemoryLib.h>\r
17#include <Library/UefiBootServicesTableLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Library/DpcLib.h>\r
20\r
21\r
22GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList = {\r
23 &mActiveIpIoList,\r
24 &mActiveIpIoList\r
25};\r
26\r
27GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData = {\r
28 EFI_IP_PROTO_UDP,\r
29 FALSE,\r
30 TRUE,\r
31 FALSE,\r
32 FALSE,\r
33 FALSE,\r
34 {{0, 0, 0, 0}},\r
35 {{0, 0, 0, 0}},\r
36 0,\r
37 255,\r
38 FALSE,\r
39 FALSE,\r
40 0,\r
41 0\r
42};\r
43\r
44GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData = {\r
45 EFI_IP_PROTO_UDP,\r
46 FALSE,\r
47 TRUE,\r
48 FALSE,\r
49 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
50 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
51 0,\r
52 255,\r
53 0,\r
54 0,\r
55 0\r
56};\r
57\r
58GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap[10] = {\r
59 {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET\r
60 {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST\r
61 {TRUE, TRUE }, // ICMP_ERR_UNREACH_PROTOCOL\r
62 {TRUE, TRUE }, // ICMP_ERR_UNREACH_PORT\r
63 {TRUE, TRUE }, // ICMP_ERR_MSGSIZE\r
64 {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL\r
65 {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS\r
66 {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS\r
67 {FALSE, FALSE}, // ICMP_ERR_QUENCH\r
68 {FALSE, TRUE } // ICMP_ERR_PARAMPROB\r
69};\r
70\r
71GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap[10] = {\r
72 {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET\r
73 {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST\r
74 {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL\r
75 {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PORT\r
76 {TRUE, TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG\r
77 {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT\r
78 {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS\r
79 {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER\r
80 {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER\r
81 {FALSE, TRUE} // ICMP6_ERR_PARAMPROB_IPV6OPTION\r
82};\r
83\r
84\r
85/**\r
86 Notify function for IP transmit token.\r
87\r
88 @param[in] Context The context passed in by the event notifier.\r
89\r
90**/\r
91VOID\r
92EFIAPI\r
93IpIoTransmitHandlerDpc (\r
94 IN VOID *Context\r
95 );\r
96\r
97\r
98/**\r
99 Notify function for IP transmit token.\r
100\r
101 @param[in] Event The event signaled.\r
102 @param[in] Context The context passed in by the event notifier.\r
103\r
104**/\r
105VOID\r
106EFIAPI\r
107IpIoTransmitHandler (\r
108 IN EFI_EVENT Event,\r
109 IN VOID *Context\r
110 );\r
111\r
112\r
113/**\r
114 This function create an IP child ,open the IP protocol, and return the opened\r
115 IP protocol as Interface.\r
116\r
117 @param[in] ControllerHandle The controller handle.\r
118 @param[in] ImageHandle The image handle.\r
119 @param[in] ChildHandle Pointer to the buffer to save the IP child handle.\r
120 @param[in] IpVersion The version of the IP protocol to use, either\r
121 IPv4 or IPv6.\r
122 @param[out] Interface Pointer used to get the IP protocol interface.\r
123\r
124 @retval EFI_SUCCESS The IP child is created and the IP protocol\r
125 interface is retrieved.\r
126 @retval EFI_UNSUPPORTED Upsupported IpVersion.\r
127 @retval Others The required operation failed.\r
128\r
129**/\r
130EFI_STATUS\r
131IpIoCreateIpChildOpenProtocol (\r
132 IN EFI_HANDLE ControllerHandle,\r
133 IN EFI_HANDLE ImageHandle,\r
134 IN EFI_HANDLE *ChildHandle,\r
135 IN UINT8 IpVersion,\r
136 OUT VOID **Interface\r
137 )\r
138{\r
139 EFI_STATUS Status;\r
140 EFI_GUID *ServiceBindingGuid;\r
141 EFI_GUID *IpProtocolGuid;\r
142\r
143 if (IpVersion == IP_VERSION_4) {\r
144 ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;\r
145 IpProtocolGuid = &gEfiIp4ProtocolGuid;\r
146 } else if (IpVersion == IP_VERSION_6){\r
147 ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;\r
148 IpProtocolGuid = &gEfiIp6ProtocolGuid;\r
149 } else {\r
150 return EFI_UNSUPPORTED;\r
151 }\r
152\r
153 //\r
154 // Create an IP child.\r
155 //\r
156 Status = NetLibCreateServiceChild (\r
157 ControllerHandle,\r
158 ImageHandle,\r
159 ServiceBindingGuid,\r
160 ChildHandle\r
161 );\r
162 if (EFI_ERROR (Status)) {\r
163 return Status;\r
164 }\r
165\r
166 //\r
167 // Open the IP protocol installed on the *ChildHandle.\r
168 //\r
169 Status = gBS->OpenProtocol (\r
170 *ChildHandle,\r
171 IpProtocolGuid,\r
172 Interface,\r
173 ImageHandle,\r
174 ControllerHandle,\r
175 EFI_OPEN_PROTOCOL_BY_DRIVER\r
176 );\r
177 if (EFI_ERROR (Status)) {\r
178 //\r
179 // On failure, destroy the IP child.\r
180 //\r
181 NetLibDestroyServiceChild (\r
182 ControllerHandle,\r
183 ImageHandle,\r
184 ServiceBindingGuid,\r
185 *ChildHandle\r
186 );\r
187 }\r
188\r
189 return Status;\r
190}\r
191\r
192\r
193/**\r
194 This function close the previously openned IP protocol and destroy the IP child.\r
195\r
196 @param[in] ControllerHandle The controller handle.\r
197 @param[in] ImageHandle The image handle.\r
198 @param[in] ChildHandle The child handle of the IP child.\r
199 @param[in] IpVersion The version of the IP protocol to use, either\r
200 IPv4 or IPv6.\r
201\r
202 @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child\r
203 is destroyed.\r
204 @retval EFI_UNSUPPORTED Upsupported IpVersion.\r
205 @retval Others The required operation failed.\r
206\r
207**/\r
208EFI_STATUS\r
209IpIoCloseProtocolDestroyIpChild (\r
210 IN EFI_HANDLE ControllerHandle,\r
211 IN EFI_HANDLE ImageHandle,\r
212 IN EFI_HANDLE ChildHandle,\r
213 IN UINT8 IpVersion\r
214 )\r
215{\r
216 EFI_STATUS Status;\r
217 EFI_GUID *ServiceBindingGuid;\r
218 EFI_GUID *IpProtocolGuid;\r
219\r
220 if (IpVersion == IP_VERSION_4) {\r
221 ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;\r
222 IpProtocolGuid = &gEfiIp4ProtocolGuid;\r
223 } else if (IpVersion == IP_VERSION_6) {\r
224 ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;\r
225 IpProtocolGuid = &gEfiIp6ProtocolGuid;\r
226 } else {\r
227 return EFI_UNSUPPORTED;\r
228 }\r
229\r
230 //\r
231 // Close the previously openned IP protocol.\r
232 //\r
233 Status = gBS->CloseProtocol (\r
234 ChildHandle,\r
235 IpProtocolGuid,\r
236 ImageHandle,\r
237 ControllerHandle\r
238 );\r
239 if (EFI_ERROR (Status)) {\r
240 return Status;\r
241 }\r
242\r
243 //\r
244 // Destroy the IP child.\r
245 //\r
246 return NetLibDestroyServiceChild (\r
247 ControllerHandle,\r
248 ImageHandle,\r
249 ServiceBindingGuid,\r
250 ChildHandle\r
251 );\r
252}\r
253\r
254/**\r
255 This function handles ICMPv4 packets. It is the worker function of\r
256 IpIoIcmpHandler.\r
257\r
258 @param[in] IpIo Pointer to the IP_IO instance.\r
259 @param[in, out] Pkt Pointer to the ICMPv4 packet.\r
260 @param[in] Session Pointer to the net session of this ICMPv4 packet.\r
261\r
262 @retval EFI_SUCCESS The ICMPv4 packet is handled successfully.\r
263 @retval EFI_ABORTED This type of ICMPv4 packet is not supported.\r
264\r
265**/\r
266EFI_STATUS\r
267IpIoIcmpv4Handler (\r
268 IN IP_IO *IpIo,\r
269 IN OUT NET_BUF *Pkt,\r
270 IN EFI_NET_SESSION_DATA *Session\r
271 )\r
272{\r
273 IP4_ICMP_ERROR_HEAD *IcmpHdr;\r
274 EFI_IP4_HEADER *IpHdr;\r
275 UINT8 IcmpErr;\r
276 UINT8 *PayLoadHdr;\r
277 UINT8 Type;\r
278 UINT8 Code;\r
279 UINT32 TrimBytes;\r
280\r
281 ASSERT (IpIo != NULL);\r
282 ASSERT (Pkt != NULL);\r
283 ASSERT (Session != NULL);\r
284 ASSERT (IpIo->IpVersion == IP_VERSION_4);\r
285\r
286 //\r
287 // Check the ICMP packet length.\r
288 //\r
289 if (Pkt->TotalSize < sizeof (IP4_ICMP_ERROR_HEAD)) {\r
290 return EFI_ABORTED;\r
291 }\r
292\r
293 IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);\r
294 IpHdr = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);\r
295\r
296 if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {\r
297\r
298 return EFI_ABORTED;\r
299 }\r
300\r
301 Type = IcmpHdr->Head.Type;\r
302 Code = IcmpHdr->Head.Code;\r
303\r
304 //\r
305 // Analyze the ICMP Error in this ICMP pkt\r
306 //\r
307 switch (Type) {\r
308 case ICMP_TYPE_UNREACH:\r
309 switch (Code) {\r
310 case ICMP_CODE_UNREACH_NET:\r
311 case ICMP_CODE_UNREACH_HOST:\r
312 case ICMP_CODE_UNREACH_PROTOCOL:\r
313 case ICMP_CODE_UNREACH_PORT:\r
314 case ICMP_CODE_UNREACH_SRCFAIL:\r
315 IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code);\r
316\r
317 break;\r
318\r
319 case ICMP_CODE_UNREACH_NEEDFRAG:\r
320 IcmpErr = ICMP_ERR_MSGSIZE;\r
321\r
322 break;\r
323\r
324 case ICMP_CODE_UNREACH_NET_UNKNOWN:\r
325 case ICMP_CODE_UNREACH_NET_PROHIB:\r
326 case ICMP_CODE_UNREACH_TOSNET:\r
327 IcmpErr = ICMP_ERR_UNREACH_NET;\r
328\r
329 break;\r
330\r
331 case ICMP_CODE_UNREACH_HOST_UNKNOWN:\r
332 case ICMP_CODE_UNREACH_ISOLATED:\r
333 case ICMP_CODE_UNREACH_HOST_PROHIB:\r
334 case ICMP_CODE_UNREACH_TOSHOST:\r
335 IcmpErr = ICMP_ERR_UNREACH_HOST;\r
336\r
337 break;\r
338\r
339 default:\r
340 return EFI_ABORTED;\r
341 }\r
342\r
343 break;\r
344\r
345 case ICMP_TYPE_TIMXCEED:\r
346 if (Code > 1) {\r
347 return EFI_ABORTED;\r
348 }\r
349\r
350 IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS);\r
351\r
352 break;\r
353\r
354 case ICMP_TYPE_PARAMPROB:\r
355 if (Code > 1) {\r
356 return EFI_ABORTED;\r
357 }\r
358\r
359 IcmpErr = ICMP_ERR_PARAMPROB;\r
360\r
361 break;\r
362\r
363 case ICMP_TYPE_SOURCEQUENCH:\r
364 if (Code != 0) {\r
365 return EFI_ABORTED;\r
366 }\r
367\r
368 IcmpErr = ICMP_ERR_QUENCH;\r
369\r
370 break;\r
371\r
372 default:\r
373 return EFI_ABORTED;\r
374 }\r
375\r
376 //\r
377 // Notify user the ICMP pkt only containing payload except\r
378 // IP and ICMP header\r
379 //\r
380 PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));\r
381 TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);\r
382\r
383 NetbufTrim (Pkt, TrimBytes, TRUE);\r
384\r
385 //\r
386 // If the input packet has invalid format, and TrimBytes is larger than\r
387 // the packet size, the NetbufTrim might trim the packet to zero.\r
388 //\r
389 if (Pkt->TotalSize != 0) {\r
390 IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);\r
391 }\r
392\r
393 return EFI_SUCCESS;\r
394}\r
395\r
396/**\r
397 This function handles ICMPv6 packets. It is the worker function of\r
398 IpIoIcmpHandler.\r
399\r
400 @param[in] IpIo Pointer to the IP_IO instance.\r
401 @param[in, out] Pkt Pointer to the ICMPv6 packet.\r
402 @param[in] Session Pointer to the net session of this ICMPv6 packet.\r
403\r
404 @retval EFI_SUCCESS The ICMPv6 packet is handled successfully.\r
405 @retval EFI_ABORTED This type of ICMPv6 packet is not supported.\r
406\r
407**/\r
408EFI_STATUS\r
409IpIoIcmpv6Handler (\r
410 IN IP_IO *IpIo,\r
411 IN OUT NET_BUF *Pkt,\r
412 IN EFI_NET_SESSION_DATA *Session\r
413 )\r
414{\r
415 IP6_ICMP_ERROR_HEAD *IcmpHdr;\r
416 EFI_IP6_HEADER *IpHdr;\r
417 UINT8 IcmpErr;\r
418 UINT8 *PayLoadHdr;\r
419 UINT8 Type;\r
420 UINT8 Code;\r
421 UINT8 NextHeader;\r
422 UINT32 TrimBytes;\r
423 BOOLEAN Flag;\r
424\r
425 ASSERT (IpIo != NULL);\r
426 ASSERT (Pkt != NULL);\r
427 ASSERT (Session != NULL);\r
428 ASSERT (IpIo->IpVersion == IP_VERSION_6);\r
429\r
430 //\r
431 // Check the ICMPv6 packet length.\r
432 //\r
433 if (Pkt->TotalSize < sizeof (IP6_ICMP_ERROR_HEAD)) {\r
434\r
435 return EFI_ABORTED;\r
436 }\r
437\r
438 IcmpHdr = NET_PROTO_HDR (Pkt, IP6_ICMP_ERROR_HEAD);\r
439 Type = IcmpHdr->Head.Type;\r
440 Code = IcmpHdr->Head.Code;\r
441\r
442 //\r
443 // Analyze the ICMPv6 Error in this ICMPv6 packet\r
444 //\r
445 switch (Type) {\r
446 case ICMP_V6_DEST_UNREACHABLE:\r
447 switch (Code) {\r
448 case ICMP_V6_NO_ROUTE_TO_DEST:\r
449 case ICMP_V6_BEYOND_SCOPE:\r
450 case ICMP_V6_ROUTE_REJECTED:\r
451 IcmpErr = ICMP6_ERR_UNREACH_NET;\r
452\r
453 break;\r
454\r
455 case ICMP_V6_COMM_PROHIBITED:\r
456 case ICMP_V6_ADDR_UNREACHABLE:\r
457 case ICMP_V6_SOURCE_ADDR_FAILED:\r
458 IcmpErr = ICMP6_ERR_UNREACH_HOST;\r
459\r
460 break;\r
461\r
462 case ICMP_V6_PORT_UNREACHABLE:\r
463 IcmpErr = ICMP6_ERR_UNREACH_PORT;\r
464\r
465 break;\r
466\r
467 default:\r
468 return EFI_ABORTED;\r
469 }\r
470\r
471 break;\r
472\r
473 case ICMP_V6_PACKET_TOO_BIG:\r
474 if (Code >= 1) {\r
475 return EFI_ABORTED;\r
476 }\r
477\r
478 IcmpErr = ICMP6_ERR_PACKAGE_TOOBIG;\r
479\r
480 break;\r
481\r
482 case ICMP_V6_TIME_EXCEEDED:\r
483 if (Code > 1) {\r
484 return EFI_ABORTED;\r
485 }\r
486\r
487 IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code);\r
488\r
489 break;\r
490\r
491 case ICMP_V6_PARAMETER_PROBLEM:\r
492 if (Code > 3) {\r
493 return EFI_ABORTED;\r
494 }\r
495\r
496 IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code);\r
497\r
498 break;\r
499\r
500 default:\r
501\r
502 return EFI_ABORTED;\r
503 }\r
504\r
505 //\r
506 // Notify user the ICMPv6 packet only containing payload except\r
507 // IPv6 basic header, extension header and ICMP header\r
508 //\r
509\r
510 IpHdr = (EFI_IP6_HEADER *) (&IcmpHdr->IpHead);\r
511 NextHeader = IpHdr->NextHeader;\r
512 PayLoadHdr = (UINT8 *) ((UINT8 *) IcmpHdr + sizeof (IP6_ICMP_ERROR_HEAD));\r
513 Flag = TRUE;\r
514\r
515 do {\r
516 switch (NextHeader) {\r
517 case EFI_IP_PROTO_UDP:\r
518 case EFI_IP_PROTO_TCP:\r
519 case EFI_IP_PROTO_ICMP:\r
520 case IP6_NO_NEXT_HEADER:\r
521 Flag = FALSE;\r
522\r
523 break;\r
524\r
525 case IP6_HOP_BY_HOP:\r
526 case IP6_DESTINATION:\r
527 //\r
528 // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including\r
529 // the first 8 octets.\r
530 //\r
531 NextHeader = *(PayLoadHdr);\r
532 PayLoadHdr = (UINT8 *) (PayLoadHdr + (*(PayLoadHdr + 1) + 1) * 8);\r
533\r
534 break;\r
535\r
536 case IP6_FRAGMENT:\r
537 //\r
538 // The Fragment Header Length is 8 octets.\r
539 //\r
540 NextHeader = *(PayLoadHdr);\r
541 PayLoadHdr = (UINT8 *) (PayLoadHdr + 8);\r
542\r
543 break;\r
544\r
545 default:\r
546\r
547 return EFI_ABORTED;\r
548 }\r
549 } while (Flag);\r
550\r
551 TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);\r
552\r
553 NetbufTrim (Pkt, TrimBytes, TRUE);\r
554\r
555 //\r
556 // If the input packet has invalid format, and TrimBytes is larger than\r
557 // the packet size, the NetbufTrim might trim the packet to zero.\r
558 //\r
559 if (Pkt->TotalSize != 0) {\r
560 IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);\r
561 }\r
562\r
563 return EFI_SUCCESS;\r
564}\r
565\r
566/**\r
567 This function handles ICMP packets.\r
568\r
569 @param[in] IpIo Pointer to the IP_IO instance.\r
570 @param[in, out] Pkt Pointer to the ICMP packet.\r
571 @param[in] Session Pointer to the net session of this ICMP packet.\r
572\r
573 @retval EFI_SUCCESS The ICMP packet is handled successfully.\r
574 @retval EFI_ABORTED This type of ICMP packet is not supported.\r
575 @retval EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.\r
576\r
577**/\r
578EFI_STATUS\r
579IpIoIcmpHandler (\r
580 IN IP_IO *IpIo,\r
581 IN OUT NET_BUF *Pkt,\r
582 IN EFI_NET_SESSION_DATA *Session\r
583 )\r
584{\r
585\r
586 if (IpIo->IpVersion == IP_VERSION_4) {\r
587\r
588 return IpIoIcmpv4Handler (IpIo, Pkt, Session);\r
589\r
590 } else if (IpIo->IpVersion == IP_VERSION_6) {\r
591\r
592 return IpIoIcmpv6Handler (IpIo, Pkt, Session);\r
593\r
594 } else {\r
595\r
596 return EFI_UNSUPPORTED;\r
597 }\r
598}\r
599\r
600\r
601/**\r
602 Free function for receive token of IP_IO. It is used to\r
603 signal the recycle event to notify IP to recycle the\r
604 data buffer.\r
605\r
606 @param[in] Event The event to be signaled.\r
607\r
608**/\r
609VOID\r
610EFIAPI\r
611IpIoExtFree (\r
612 IN VOID *Event\r
613 )\r
614{\r
615 gBS->SignalEvent ((EFI_EVENT) Event);\r
616}\r
617\r
618\r
619/**\r
620 Create a send entry to wrap a packet before sending\r
621 out it through IP.\r
622\r
623 @param[in, out] IpIo Pointer to the IP_IO instance.\r
624 @param[in, out] Pkt Pointer to the packet.\r
625 @param[in] Sender Pointer to the IP sender.\r
626 @param[in] Context Pointer to the context.\r
627 @param[in] NotifyData Pointer to the notify data.\r
628 @param[in] Dest Pointer to the destination IP address.\r
629 @param[in] Override Pointer to the overriden IP_IO data.\r
630\r
631 @return Pointer to the data structure created to wrap the packet. If any error occurs,\r
632 then return NULL.\r
633\r
634**/\r
635IP_IO_SEND_ENTRY *\r
636IpIoCreateSndEntry (\r
637 IN OUT IP_IO *IpIo,\r
638 IN OUT NET_BUF *Pkt,\r
639 IN IP_IO_IP_PROTOCOL Sender,\r
640 IN VOID *Context OPTIONAL,\r
641 IN VOID *NotifyData OPTIONAL,\r
642 IN EFI_IP_ADDRESS *Dest OPTIONAL,\r
643 IN IP_IO_OVERRIDE *Override\r
644 )\r
645{\r
646 IP_IO_SEND_ENTRY *SndEntry;\r
647 EFI_EVENT Event;\r
648 EFI_STATUS Status;\r
649 NET_FRAGMENT *ExtFragment;\r
650 UINT32 FragmentCount;\r
651 IP_IO_OVERRIDE *OverrideData;\r
652 IP_IO_IP_TX_DATA *TxData;\r
653 EFI_IP4_TRANSMIT_DATA *Ip4TxData;\r
654 EFI_IP6_TRANSMIT_DATA *Ip6TxData;\r
655\r
656 if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {\r
657 return NULL;\r
658 }\r
659\r
660 Event = NULL;\r
661 TxData = NULL;\r
662 OverrideData = NULL;\r
663\r
664 //\r
665 // Allocate resource for SndEntry\r
666 //\r
667 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));\r
668 if (NULL == SndEntry) {\r
669 return NULL;\r
670 }\r
671\r
672 Status = gBS->CreateEvent (\r
673 EVT_NOTIFY_SIGNAL,\r
674 TPL_NOTIFY,\r
675 IpIoTransmitHandler,\r
676 SndEntry,\r
677 &Event\r
678 );\r
679 if (EFI_ERROR (Status)) {\r
680 goto ON_ERROR;\r
681 }\r
682\r
683 FragmentCount = Pkt->BlockOpNum;\r
684\r
685 //\r
686 // Allocate resource for TxData\r
687 //\r
688 TxData = (IP_IO_IP_TX_DATA *) AllocatePool (\r
689 sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)\r
690 );\r
691\r
692 if (NULL == TxData) {\r
693 goto ON_ERROR;\r
694 }\r
695\r
696 //\r
697 // Build a fragment table to contain the fragments in the packet.\r
698 //\r
699 if (IpIo->IpVersion == IP_VERSION_4) {\r
700 ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;\r
701 } else {\r
702 ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;\r
703 }\r
704\r
705 NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);\r
706\r
707\r
708 //\r
709 // Allocate resource for OverrideData if needed\r
710 //\r
711 if (NULL != Override) {\r
712\r
713 OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);\r
714 if (NULL == OverrideData) {\r
715 goto ON_ERROR;\r
716 }\r
717 }\r
718\r
719 //\r
720 // Set other fields of TxData except the fragment table\r
721 //\r
722 if (IpIo->IpVersion == IP_VERSION_4) {\r
723\r
724 Ip4TxData = &TxData->Ip4TxData;\r
725\r
726 IP4_COPY_ADDRESS (&Ip4TxData->DestinationAddress, Dest);\r
727\r
728 Ip4TxData->OverrideData = &OverrideData->Ip4OverrideData;\r
729 Ip4TxData->OptionsLength = 0;\r
730 Ip4TxData->OptionsBuffer = NULL;\r
731 Ip4TxData->TotalDataLength = Pkt->TotalSize;\r
732 Ip4TxData->FragmentCount = FragmentCount;\r
733\r
734 //\r
735 // Set the fields of SndToken\r
736 //\r
737 SndEntry->SndToken.Ip4Token.Event = Event;\r
738 SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;\r
739 } else {\r
740\r
741 Ip6TxData = &TxData->Ip6TxData;\r
742\r
743 if (Dest != NULL) {\r
744 CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));\r
745 } else {\r
746 ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));\r
747 }\r
748\r
749 Ip6TxData->OverrideData = &OverrideData->Ip6OverrideData;\r
750 Ip6TxData->DataLength = Pkt->TotalSize;\r
751 Ip6TxData->FragmentCount = FragmentCount;\r
752 Ip6TxData->ExtHdrsLength = 0;\r
753 Ip6TxData->ExtHdrs = NULL;\r
754\r
755 //\r
756 // Set the fields of SndToken\r
757 //\r
758 SndEntry->SndToken.Ip6Token.Event = Event;\r
759 SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;\r
760 }\r
761\r
762 //\r
763 // Set the fields of SndEntry\r
764 //\r
765 SndEntry->IpIo = IpIo;\r
766 SndEntry->Ip = Sender;\r
767 SndEntry->Context = Context;\r
768 SndEntry->NotifyData = NotifyData;\r
769\r
770 SndEntry->Pkt = Pkt;\r
771 NET_GET_REF (Pkt);\r
772\r
773 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);\r
774\r
775 return SndEntry;\r
776\r
777ON_ERROR:\r
778\r
779 if (OverrideData != NULL) {\r
780 FreePool (OverrideData);\r
781 }\r
782\r
783 if (TxData != NULL) {\r
784 FreePool (TxData);\r
785 }\r
786\r
787 if (SndEntry != NULL) {\r
788 FreePool (SndEntry);\r
789 }\r
790\r
791 if (Event != NULL) {\r
792 gBS->CloseEvent (Event);\r
793 }\r
794\r
795 return NULL;\r
796}\r
797\r
798\r
799/**\r
800 Destroy the SndEntry.\r
801\r
802 This function pairs with IpIoCreateSndEntry().\r
803\r
804 @param[in] SndEntry Pointer to the send entry to be destroyed.\r
805\r
806**/\r
807VOID\r
808IpIoDestroySndEntry (\r
809 IN IP_IO_SEND_ENTRY *SndEntry\r
810 )\r
811{\r
812 EFI_EVENT Event;\r
813 IP_IO_IP_TX_DATA *TxData;\r
814 IP_IO_OVERRIDE *Override;\r
815\r
816 if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {\r
817 Event = SndEntry->SndToken.Ip4Token.Event;\r
818 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;\r
819 Override = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;\r
820 } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {\r
821 Event = SndEntry->SndToken.Ip6Token.Event;\r
822 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;\r
823 Override = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;\r
824 } else {\r
825 return ;\r
826 }\r
827\r
828 gBS->CloseEvent (Event);\r
829\r
830 FreePool (TxData);\r
831\r
832 if (NULL != Override) {\r
833 FreePool (Override);\r
834 }\r
835\r
836 NetbufFree (SndEntry->Pkt);\r
837\r
838 RemoveEntryList (&SndEntry->Entry);\r
839\r
840 FreePool (SndEntry);\r
841}\r
842\r
843\r
844/**\r
845 Notify function for IP transmit token.\r
846\r
847 @param[in] Context The context passed in by the event notifier.\r
848\r
849**/\r
850VOID\r
851EFIAPI\r
852IpIoTransmitHandlerDpc (\r
853 IN VOID *Context\r
854 )\r
855{\r
856 IP_IO *IpIo;\r
857 IP_IO_SEND_ENTRY *SndEntry;\r
858 EFI_STATUS Status;\r
859\r
860 SndEntry = (IP_IO_SEND_ENTRY *) Context;\r
861\r
862 IpIo = SndEntry->IpIo;\r
863\r
864 if (IpIo->IpVersion == IP_VERSION_4) {\r
865 Status = SndEntry->SndToken.Ip4Token.Status;\r
866 } else if (IpIo->IpVersion == IP_VERSION_6){\r
867 Status = SndEntry->SndToken.Ip6Token.Status;\r
868 } else {\r
869 return ;\r
870 }\r
871\r
872 if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {\r
873 IpIo->PktSentNotify (\r
874 Status,\r
875 SndEntry->Context,\r
876 SndEntry->Ip,\r
877 SndEntry->NotifyData\r
878 );\r
879 }\r
880\r
881 IpIoDestroySndEntry (SndEntry);\r
882}\r
883\r
884\r
885/**\r
886 Notify function for IP transmit token.\r
887\r
888 @param[in] Event The event signaled.\r
889 @param[in] Context The context passed in by the event notifier.\r
890\r
891**/\r
892VOID\r
893EFIAPI\r
894IpIoTransmitHandler (\r
895 IN EFI_EVENT Event,\r
896 IN VOID *Context\r
897 )\r
898{\r
899 //\r
900 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK\r
901 //\r
902 QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);\r
903}\r
904\r
905\r
906/**\r
907 The dummy handler for the dummy IP receive token.\r
908\r
909 @param[in] Context The context passed in by the event notifier.\r
910\r
911**/\r
912VOID\r
913EFIAPI\r
914IpIoDummyHandlerDpc (\r
915 IN VOID *Context\r
916 )\r
917{\r
918 IP_IO_IP_INFO *IpInfo;\r
919 EFI_STATUS Status;\r
920 EFI_EVENT RecycleEvent;\r
921\r
922 IpInfo = (IP_IO_IP_INFO *) Context;\r
923\r
924 if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {\r
925 return ;\r
926 }\r
927\r
928 RecycleEvent = NULL;\r
929\r
930 if (IpInfo->IpVersion == IP_VERSION_4) {\r
931 Status = IpInfo->DummyRcvToken.Ip4Token.Status;\r
932\r
933 if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {\r
934 RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;\r
935 }\r
936 } else {\r
937 Status = IpInfo->DummyRcvToken.Ip6Token.Status;\r
938\r
939 if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {\r
940 RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;\r
941 }\r
942 }\r
943\r
944\r
945\r
946 if (EFI_ABORTED == Status) {\r
947 //\r
948 // The reception is actively aborted by the consumer, directly return.\r
949 //\r
950 return;\r
951 } else if (EFI_SUCCESS == Status) {\r
952 //\r
953 // Recycle the RxData.\r
954 //\r
955 ASSERT (RecycleEvent != NULL);\r
956\r
957 gBS->SignalEvent (RecycleEvent);\r
958 }\r
959\r
960 //\r
961 // Continue the receive.\r
962 //\r
963 if (IpInfo->IpVersion == IP_VERSION_4) {\r
964 IpInfo->Ip.Ip4->Receive (\r
965 IpInfo->Ip.Ip4,\r
966 &IpInfo->DummyRcvToken.Ip4Token\r
967 );\r
968 } else {\r
969 IpInfo->Ip.Ip6->Receive (\r
970 IpInfo->Ip.Ip6,\r
971 &IpInfo->DummyRcvToken.Ip6Token\r
972 );\r
973 }\r
974}\r
975\r
976\r
977/**\r
978 This function add IpIoDummyHandlerDpc to the end of the DPC queue.\r
979\r
980 @param[in] Event The event signaled.\r
981 @param[in] Context The context passed in by the event notifier.\r
982\r
983**/\r
984VOID\r
985EFIAPI\r
986IpIoDummyHandler (\r
987 IN EFI_EVENT Event,\r
988 IN VOID *Context\r
989 )\r
990{\r
991 //\r
992 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK\r
993 //\r
994 QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);\r
995}\r
996\r
997\r
998/**\r
999 Notify function for the IP receive token, used to process\r
1000 the received IP packets.\r
1001\r
1002 @param[in] Context The context passed in by the event notifier.\r
1003\r
1004**/\r
1005VOID\r
1006EFIAPI\r
1007IpIoListenHandlerDpc (\r
1008 IN VOID *Context\r
1009 )\r
1010{\r
1011 IP_IO *IpIo;\r
1012 EFI_STATUS Status;\r
1013 IP_IO_IP_RX_DATA *RxData;\r
1014 EFI_NET_SESSION_DATA Session;\r
1015 NET_BUF *Pkt;\r
1016\r
1017 IpIo = (IP_IO *) Context;\r
1018\r
1019 if (IpIo->IpVersion == IP_VERSION_4) {\r
1020 Status = IpIo->RcvToken.Ip4Token.Status;\r
1021 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;\r
1022 } else if (IpIo->IpVersion == IP_VERSION_6) {\r
1023 Status = IpIo->RcvToken.Ip6Token.Status;\r
1024 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;\r
1025 } else {\r
1026 return;\r
1027 }\r
1028\r
1029 if (EFI_ABORTED == Status) {\r
1030 //\r
1031 // The reception is actively aborted by the consumer, directly return.\r
1032 //\r
1033 return;\r
1034 }\r
1035\r
1036 if ((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) {\r
1037 //\r
1038 // Only process the normal packets and the icmp error packets.\r
1039 //\r
1040 if (RxData != NULL) {\r
1041 goto CleanUp;\r
1042 } else {\r
1043 goto Resume;\r
1044 }\r
1045 }\r
1046\r
1047 //\r
1048 // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).\r
1049 //\r
1050 ASSERT (RxData != NULL);\r
1051 if (RxData == NULL) {\r
1052 goto Resume;\r
1053 }\r
1054\r
1055 if (NULL == IpIo->PktRcvdNotify) {\r
1056 goto CleanUp;\r
1057 }\r
1058\r
1059 if (IpIo->IpVersion == IP_VERSION_4) {\r
1060 ASSERT (RxData->Ip4RxData.Header != NULL);\r
1061 if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress))) {\r
1062 //\r
1063 // The source address is a broadcast address, discard it.\r
1064 //\r
1065 goto CleanUp;\r
1066 }\r
1067 if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&\r
1068 (IpIo->SubnetMask != 0) &&\r
1069 IP4_NET_EQUAL (IpIo->StationIp, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask) &&\r
1070 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask)) {\r
1071 //\r
1072 // The source address doesn't match StationIp and it's not a unicast IP address, discard it.\r
1073 //\r
1074 goto CleanUp;\r
1075 }\r
1076\r
1077 if (RxData->Ip4RxData.DataLength == 0) {\r
1078 //\r
1079 // Discard zero length data payload packet.\r
1080 //\r
1081 goto CleanUp;\r
1082 }\r
1083\r
1084 //\r
1085 // The fragment should always be valid for non-zero length packet.\r
1086 //\r
1087 ASSERT (RxData->Ip4RxData.FragmentCount != 0);\r
1088\r
1089 //\r
1090 // Create a netbuffer representing IPv4 packet\r
1091 //\r
1092 Pkt = NetbufFromExt (\r
1093 (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,\r
1094 RxData->Ip4RxData.FragmentCount,\r
1095 0,\r
1096 0,\r
1097 IpIoExtFree,\r
1098 RxData->Ip4RxData.RecycleSignal\r
1099 );\r
1100 if (NULL == Pkt) {\r
1101 goto CleanUp;\r
1102 }\r
1103\r
1104 //\r
1105 // Create a net session\r
1106 //\r
1107 Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);\r
1108 Session.Dest.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);\r
1109 Session.IpHdr.Ip4Hdr = RxData->Ip4RxData.Header;\r
1110 Session.IpHdrLen = RxData->Ip4RxData.HeaderLength;\r
1111 Session.IpVersion = IP_VERSION_4;\r
1112 } else {\r
1113 ASSERT (RxData->Ip6RxData.Header != NULL);\r
1114 if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {\r
1115 goto CleanUp;\r
1116 }\r
1117\r
1118 if (RxData->Ip6RxData.DataLength == 0) {\r
1119 //\r
1120 // Discard zero length data payload packet.\r
1121 //\r
1122 goto CleanUp;\r
1123 }\r
1124\r
1125 //\r
1126 // The fragment should always be valid for non-zero length packet.\r
1127 //\r
1128 ASSERT (RxData->Ip6RxData.FragmentCount != 0);\r
1129\r
1130 //\r
1131 // Create a netbuffer representing IPv6 packet\r
1132 //\r
1133 Pkt = NetbufFromExt (\r
1134 (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,\r
1135 RxData->Ip6RxData.FragmentCount,\r
1136 0,\r
1137 0,\r
1138 IpIoExtFree,\r
1139 RxData->Ip6RxData.RecycleSignal\r
1140 );\r
1141 if (NULL == Pkt) {\r
1142 goto CleanUp;\r
1143 }\r
1144\r
1145 //\r
1146 // Create a net session\r
1147 //\r
1148 CopyMem (\r
1149 &Session.Source,\r
1150 &RxData->Ip6RxData.Header->SourceAddress,\r
1151 sizeof(EFI_IPv6_ADDRESS)\r
1152 );\r
1153 CopyMem (\r
1154 &Session.Dest,\r
1155 &RxData->Ip6RxData.Header->DestinationAddress,\r
1156 sizeof(EFI_IPv6_ADDRESS)\r
1157 );\r
1158 Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;\r
1159 Session.IpHdrLen = RxData->Ip6RxData.HeaderLength;\r
1160 Session.IpVersion = IP_VERSION_6;\r
1161 }\r
1162\r
1163 if (EFI_SUCCESS == Status) {\r
1164\r
1165 IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);\r
1166 } else {\r
1167 //\r
1168 // Status is EFI_ICMP_ERROR\r
1169 //\r
1170 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);\r
1171 if (EFI_ERROR (Status)) {\r
1172 NetbufFree (Pkt);\r
1173 }\r
1174 }\r
1175\r
1176 goto Resume;\r
1177\r
1178CleanUp:\r
1179\r
1180 if (IpIo->IpVersion == IP_VERSION_4){\r
1181 gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);\r
1182 } else {\r
1183 gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);\r
1184 }\r
1185\r
1186Resume:\r
1187\r
1188 if (IpIo->IpVersion == IP_VERSION_4){\r
1189 IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));\r
1190 } else {\r
1191 IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));\r
1192 }\r
1193}\r
1194\r
1195/**\r
1196 This function add IpIoListenHandlerDpc to the end of the DPC queue.\r
1197\r
1198 @param[in] Event The event signaled.\r
1199 @param[in] Context The context passed in by the event notifier.\r
1200\r
1201**/\r
1202VOID\r
1203EFIAPI\r
1204IpIoListenHandler (\r
1205 IN EFI_EVENT Event,\r
1206 IN VOID *Context\r
1207 )\r
1208{\r
1209 //\r
1210 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
1211 //\r
1212 QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);\r
1213}\r
1214\r
1215\r
1216/**\r
1217 Create a new IP_IO instance.\r
1218\r
1219 If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
1220\r
1221 This function uses IP4/IP6 service binding protocol in Controller to create\r
1222 an IP4/IP6 child (aka IP4/IP6 instance).\r
1223\r
1224 @param[in] Image The image handle of the driver or application that\r
1225 consumes IP_IO.\r
1226 @param[in] Controller The controller handle that has IP4 or IP6 service\r
1227 binding protocol installed.\r
1228 @param[in] IpVersion The version of the IP protocol to use, either\r
1229 IPv4 or IPv6.\r
1230\r
1231 @return Pointer to a newly created IP_IO instance, or NULL if failed.\r
1232\r
1233**/\r
1234IP_IO *\r
1235EFIAPI\r
1236IpIoCreate (\r
1237 IN EFI_HANDLE Image,\r
1238 IN EFI_HANDLE Controller,\r
1239 IN UINT8 IpVersion\r
1240 )\r
1241{\r
1242 EFI_STATUS Status;\r
1243 IP_IO *IpIo;\r
1244 EFI_EVENT Event;\r
1245\r
1246 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1247\r
1248 IpIo = AllocateZeroPool (sizeof (IP_IO));\r
1249 if (NULL == IpIo) {\r
1250 return NULL;\r
1251 }\r
1252\r
1253 InitializeListHead (&(IpIo->PendingSndList));\r
1254 InitializeListHead (&(IpIo->IpList));\r
1255 IpIo->Controller = Controller;\r
1256 IpIo->Image = Image;\r
1257 IpIo->IpVersion = IpVersion;\r
1258 Event = NULL;\r
1259\r
1260 Status = gBS->CreateEvent (\r
1261 EVT_NOTIFY_SIGNAL,\r
1262 TPL_NOTIFY,\r
1263 IpIoListenHandler,\r
1264 IpIo,\r
1265 &Event\r
1266 );\r
1267 if (EFI_ERROR (Status)) {\r
1268 goto ReleaseIpIo;\r
1269 }\r
1270\r
1271 if (IpVersion == IP_VERSION_4) {\r
1272 IpIo->RcvToken.Ip4Token.Event = Event;\r
1273 } else {\r
1274 IpIo->RcvToken.Ip6Token.Event = Event;\r
1275 }\r
1276\r
1277 //\r
1278 // Create an IP child and open IP protocol\r
1279 //\r
1280 Status = IpIoCreateIpChildOpenProtocol (\r
1281 Controller,\r
1282 Image,\r
1283 &IpIo->ChildHandle,\r
1284 IpVersion,\r
1285 (VOID **) & (IpIo->Ip)\r
1286 );\r
1287 if (EFI_ERROR (Status)) {\r
1288 goto ReleaseIpIo;\r
1289 }\r
1290\r
1291 return IpIo;\r
1292\r
1293ReleaseIpIo:\r
1294\r
1295 if (Event != NULL) {\r
1296 gBS->CloseEvent (Event);\r
1297 }\r
1298\r
1299 gBS->FreePool (IpIo);\r
1300\r
1301 return NULL;\r
1302}\r
1303\r
1304\r
1305/**\r
1306 Open an IP_IO instance for use.\r
1307\r
1308 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
1309\r
1310 This function is called after IpIoCreate(). It is used for configuring the IP\r
1311 instance and register the callbacks and their context data for sending and\r
1312 receiving IP packets.\r
1313\r
1314 @param[in, out] IpIo Pointer to an IP_IO instance that needs\r
1315 to open.\r
1316 @param[in] OpenData The configuration data and callbacks for\r
1317 the IP_IO instance.\r
1318\r
1319 @retval EFI_SUCCESS The IP_IO instance opened with OpenData\r
1320 successfully.\r
1321 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to\r
1322 reopen it.\r
1323 @retval EFI_UNSUPPORTED IPv4 RawData mode is no supported.\r
1324 @retval EFI_INVALID_PARAMETER Invalid input parameter.\r
1325 @retval Others Error condition occurred.\r
1326\r
1327**/\r
1328EFI_STATUS\r
1329EFIAPI\r
1330IpIoOpen (\r
1331 IN OUT IP_IO *IpIo,\r
1332 IN IP_IO_OPEN_DATA *OpenData\r
1333 )\r
1334{\r
1335 EFI_STATUS Status;\r
1336 UINT8 IpVersion;\r
1337\r
1338 if (IpIo == NULL || OpenData == NULL) {\r
1339 return EFI_INVALID_PARAMETER;\r
1340 }\r
1341\r
1342 if (IpIo->IsConfigured) {\r
1343 return EFI_ACCESS_DENIED;\r
1344 }\r
1345\r
1346 IpVersion = IpIo->IpVersion;\r
1347\r
1348 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1349\r
1350 //\r
1351 // configure ip\r
1352 //\r
1353 if (IpVersion == IP_VERSION_4){\r
1354 //\r
1355 // RawData mode is no supported.\r
1356 //\r
1357 ASSERT (!OpenData->IpConfigData.Ip4CfgData.RawData);\r
1358 if (OpenData->IpConfigData.Ip4CfgData.RawData) {\r
1359 return EFI_UNSUPPORTED;\r
1360 }\r
1361\r
1362 if (!OpenData->IpConfigData.Ip4CfgData.UseDefaultAddress) {\r
1363 IpIo->StationIp = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.StationAddress);\r
1364 IpIo->SubnetMask = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.SubnetMask);\r
1365 }\r
1366\r
1367 Status = IpIo->Ip.Ip4->Configure (\r
1368 IpIo->Ip.Ip4,\r
1369 &OpenData->IpConfigData.Ip4CfgData\r
1370 );\r
1371 } else {\r
1372\r
1373 Status = IpIo->Ip.Ip6->Configure (\r
1374 IpIo->Ip.Ip6,\r
1375 &OpenData->IpConfigData.Ip6CfgData\r
1376 );\r
1377 }\r
1378\r
1379 if (EFI_ERROR (Status)) {\r
1380 return Status;\r
1381 }\r
1382\r
1383 //\r
1384 // @bug To delete the default route entry in this Ip, if it is:\r
1385 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified\r
1386 // @bug its code\r
1387 //\r
1388 if (IpVersion == IP_VERSION_4){\r
1389 Status = IpIo->Ip.Ip4->Routes (\r
1390 IpIo->Ip.Ip4,\r
1391 TRUE,\r
1392 &mZeroIp4Addr,\r
1393 &mZeroIp4Addr,\r
1394 &mZeroIp4Addr\r
1395 );\r
1396\r
1397 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {\r
1398 return Status;\r
1399 }\r
1400 }\r
1401\r
1402 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;\r
1403 IpIo->PktSentNotify = OpenData->PktSentNotify;\r
1404\r
1405 IpIo->RcvdContext = OpenData->RcvdContext;\r
1406 IpIo->SndContext = OpenData->SndContext;\r
1407\r
1408 if (IpVersion == IP_VERSION_4){\r
1409 IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;\r
1410\r
1411 //\r
1412 // start to listen incoming packet\r
1413 //\r
1414 Status = IpIo->Ip.Ip4->Receive (\r
1415 IpIo->Ip.Ip4,\r
1416 &(IpIo->RcvToken.Ip4Token)\r
1417 );\r
1418 if (EFI_ERROR (Status)) {\r
1419 IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);\r
1420 return Status;\r
1421 }\r
1422\r
1423 } else {\r
1424\r
1425 IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;\r
1426 Status = IpIo->Ip.Ip6->Receive (\r
1427 IpIo->Ip.Ip6,\r
1428 &(IpIo->RcvToken.Ip6Token)\r
1429 );\r
1430 if (EFI_ERROR (Status)) {\r
1431 IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);\r
1432 return Status;\r
1433 }\r
1434 }\r
1435\r
1436 IpIo->IsConfigured = TRUE;\r
1437 InsertTailList (&mActiveIpIoList, &IpIo->Entry);\r
1438\r
1439 return Status;\r
1440}\r
1441\r
1442\r
1443/**\r
1444 Stop an IP_IO instance.\r
1445\r
1446 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
1447\r
1448 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all\r
1449 the pending send/receive tokens will be canceled.\r
1450\r
1451 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.\r
1452\r
1453 @retval EFI_SUCCESS The IP_IO instance stopped successfully.\r
1454 @retval EFI_INVALID_PARAMETER Invalid input parameter.\r
1455 @retval Others Error condition occurred.\r
1456\r
1457**/\r
1458EFI_STATUS\r
1459EFIAPI\r
1460IpIoStop (\r
1461 IN OUT IP_IO *IpIo\r
1462 )\r
1463{\r
1464 EFI_STATUS Status;\r
1465 IP_IO_IP_INFO *IpInfo;\r
1466 UINT8 IpVersion;\r
1467\r
1468 if (IpIo == NULL) {\r
1469 return EFI_INVALID_PARAMETER;\r
1470 }\r
1471\r
1472 if (!IpIo->IsConfigured) {\r
1473 return EFI_SUCCESS;\r
1474 }\r
1475\r
1476 IpVersion = IpIo->IpVersion;\r
1477\r
1478 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1479\r
1480 //\r
1481 // Remove the IpIo from the active IpIo list.\r
1482 //\r
1483 RemoveEntryList (&IpIo->Entry);\r
1484\r
1485 //\r
1486 // Configure NULL Ip\r
1487 //\r
1488 if (IpVersion == IP_VERSION_4) {\r
1489 Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);\r
1490 } else {\r
1491 Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);\r
1492 }\r
1493 if (EFI_ERROR (Status)) {\r
1494 return Status;\r
1495 }\r
1496\r
1497 IpIo->IsConfigured = FALSE;\r
1498\r
1499 //\r
1500 // Detroy the Ip List used by IpIo\r
1501 //\r
1502\r
1503 while (!IsListEmpty (&(IpIo->IpList))) {\r
1504 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);\r
1505\r
1506 IpIoRemoveIp (IpIo, IpInfo);\r
1507 }\r
1508\r
1509 //\r
1510 // All pending send tokens should be flushed by resetting the IP instances.\r
1511 //\r
1512 ASSERT (IsListEmpty (&IpIo->PendingSndList));\r
1513\r
1514 //\r
1515 // Close the receive event.\r
1516 //\r
1517 if (IpVersion == IP_VERSION_4){\r
1518 gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);\r
1519 } else {\r
1520 gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);\r
1521 }\r
1522\r
1523 return EFI_SUCCESS;\r
1524}\r
1525\r
1526\r
1527/**\r
1528 Destroy an IP_IO instance.\r
1529\r
1530 This function is paired with IpIoCreate(). The IP_IO will be closed first.\r
1531 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().\r
1532\r
1533 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be\r
1534 destroyed.\r
1535\r
1536 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.\r
1537 @retval Others Error condition occurred.\r
1538\r
1539**/\r
1540EFI_STATUS\r
1541EFIAPI\r
1542IpIoDestroy (\r
1543 IN OUT IP_IO *IpIo\r
1544 )\r
1545{\r
1546 EFI_STATUS Status;\r
1547\r
1548 //\r
1549 // Stop the IpIo.\r
1550 //\r
1551 Status = IpIoStop (IpIo);\r
1552 if (EFI_ERROR (Status)) {\r
1553 return Status;\r
1554 }\r
1555\r
1556 //\r
1557 // Close the IP protocol and destroy the child.\r
1558 //\r
1559 Status = IpIoCloseProtocolDestroyIpChild (\r
1560 IpIo->Controller,\r
1561 IpIo->Image,\r
1562 IpIo->ChildHandle,\r
1563 IpIo->IpVersion\r
1564 );\r
1565 if (EFI_ERROR (Status)) {\r
1566 return Status;\r
1567 }\r
1568\r
1569 gBS->FreePool (IpIo);\r
1570\r
1571 return EFI_SUCCESS;\r
1572}\r
1573\r
1574\r
1575/**\r
1576 Send out an IP packet.\r
1577\r
1578 This function is called after IpIoOpen(). The data to be sent is wrapped in\r
1579 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be\r
1580 overriden by Sender. Other sending configs, like source address and gateway\r
1581 address etc., are specified in OverrideData.\r
1582\r
1583 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP\r
1584 packet.\r
1585 @param[in, out] Pkt Pointer to the IP packet to be sent.\r
1586 @param[in] Sender The IP protocol instance used for sending.\r
1587 @param[in] Context Optional context data.\r
1588 @param[in] NotifyData Optional notify data.\r
1589 @param[in] Dest The destination IP address to send this packet to.\r
1590 This parameter is optional when using IPv6.\r
1591 @param[in] OverrideData The data to override some configuration of the IP\r
1592 instance used for sending.\r
1593\r
1594 @retval EFI_SUCCESS The operation is completed successfully.\r
1595 @retval EFI_INVALID_PARAMETER The input parameter is not correct.\r
1596 @retval EFI_NOT_STARTED The IpIo is not configured.\r
1597 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
1598 @retval Others Error condition occurred.\r
1599\r
1600**/\r
1601EFI_STATUS\r
1602EFIAPI\r
1603IpIoSend (\r
1604 IN OUT IP_IO *IpIo,\r
1605 IN OUT NET_BUF *Pkt,\r
1606 IN IP_IO_IP_INFO *Sender OPTIONAL,\r
1607 IN VOID *Context OPTIONAL,\r
1608 IN VOID *NotifyData OPTIONAL,\r
1609 IN EFI_IP_ADDRESS *Dest OPTIONAL,\r
1610 IN IP_IO_OVERRIDE *OverrideData OPTIONAL\r
1611 )\r
1612{\r
1613 EFI_STATUS Status;\r
1614 IP_IO_IP_PROTOCOL Ip;\r
1615 IP_IO_SEND_ENTRY *SndEntry;\r
1616\r
1617 if ((IpIo == NULL) || (Pkt == NULL)) {\r
1618 return EFI_INVALID_PARAMETER;\r
1619 }\r
1620\r
1621 if ((IpIo->IpVersion == IP_VERSION_4) && (Dest == NULL)) {\r
1622 return EFI_INVALID_PARAMETER;\r
1623 }\r
1624\r
1625 if (!IpIo->IsConfigured) {\r
1626 return EFI_NOT_STARTED;\r
1627 }\r
1628\r
1629 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;\r
1630\r
1631 //\r
1632 // create a new SndEntry\r
1633 //\r
1634 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);\r
1635 if (NULL == SndEntry) {\r
1636 return EFI_OUT_OF_RESOURCES;\r
1637 }\r
1638\r
1639 //\r
1640 // Send this Packet\r
1641 //\r
1642 if (IpIo->IpVersion == IP_VERSION_4){\r
1643 Status = Ip.Ip4->Transmit (\r
1644 Ip.Ip4,\r
1645 &SndEntry->SndToken.Ip4Token\r
1646 );\r
1647 } else {\r
1648 Status = Ip.Ip6->Transmit (\r
1649 Ip.Ip6,\r
1650 &SndEntry->SndToken.Ip6Token\r
1651 );\r
1652 }\r
1653\r
1654 if (EFI_ERROR (Status)) {\r
1655 IpIoDestroySndEntry (SndEntry);\r
1656 }\r
1657\r
1658 return Status;\r
1659}\r
1660\r
1661\r
1662/**\r
1663 Cancel the IP transmit token which wraps this Packet.\r
1664\r
1665 If IpIo is NULL, then ASSERT().\r
1666 If Packet is NULL, then ASSERT().\r
1667\r
1668 @param[in] IpIo Pointer to the IP_IO instance.\r
1669 @param[in] Packet Pointer to the packet of NET_BUF to cancel.\r
1670\r
1671**/\r
1672VOID\r
1673EFIAPI\r
1674IpIoCancelTxToken (\r
1675 IN IP_IO *IpIo,\r
1676 IN VOID *Packet\r
1677 )\r
1678{\r
1679 LIST_ENTRY *Node;\r
1680 IP_IO_SEND_ENTRY *SndEntry;\r
1681 IP_IO_IP_PROTOCOL Ip;\r
1682\r
1683 ASSERT ((IpIo != NULL) && (Packet != NULL));\r
1684\r
1685 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {\r
1686\r
1687 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);\r
1688\r
1689 if (SndEntry->Pkt == Packet) {\r
1690\r
1691 Ip = SndEntry->Ip;\r
1692\r
1693 if (IpIo->IpVersion == IP_VERSION_4) {\r
1694 Ip.Ip4->Cancel (\r
1695 Ip.Ip4,\r
1696 &SndEntry->SndToken.Ip4Token\r
1697 );\r
1698 } else {\r
1699 Ip.Ip6->Cancel (\r
1700 Ip.Ip6,\r
1701 &SndEntry->SndToken.Ip6Token\r
1702 );\r
1703 }\r
1704\r
1705 break;\r
1706 }\r
1707 }\r
1708\r
1709}\r
1710\r
1711\r
1712/**\r
1713 Add a new IP instance for sending data.\r
1714\r
1715 If IpIo is NULL, then ASSERT().\r
1716 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
1717\r
1718 The function is used to add the IP_IO to the IP_IO sending list. The caller\r
1719 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send\r
1720 data.\r
1721\r
1722 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP\r
1723 instance for sending purpose.\r
1724\r
1725 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.\r
1726\r
1727**/\r
1728IP_IO_IP_INFO *\r
1729EFIAPI\r
1730IpIoAddIp (\r
1731 IN OUT IP_IO *IpIo\r
1732 )\r
1733{\r
1734 EFI_STATUS Status;\r
1735 IP_IO_IP_INFO *IpInfo;\r
1736 EFI_EVENT Event;\r
1737\r
1738 ASSERT (IpIo != NULL);\r
1739 ASSERT ((IpIo->IpVersion == IP_VERSION_4) || (IpIo->IpVersion == IP_VERSION_6));\r
1740\r
1741 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));\r
1742 if (IpInfo == NULL) {\r
1743 return NULL;\r
1744 }\r
1745\r
1746 //\r
1747 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP\r
1748 // instance.\r
1749 //\r
1750 InitializeListHead (&IpInfo->Entry);\r
1751 IpInfo->ChildHandle = NULL;\r
1752 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1753 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
1754\r
1755 IpInfo->RefCnt = 1;\r
1756 IpInfo->IpVersion = IpIo->IpVersion;\r
1757\r
1758 //\r
1759 // Create the IP instance and open the IP protocol.\r
1760 //\r
1761 Status = IpIoCreateIpChildOpenProtocol (\r
1762 IpIo->Controller,\r
1763 IpIo->Image,\r
1764 &IpInfo->ChildHandle,\r
1765 IpInfo->IpVersion,\r
1766 (VOID **) &IpInfo->Ip\r
1767 );\r
1768 if (EFI_ERROR (Status)) {\r
1769 goto ReleaseIpInfo;\r
1770 }\r
1771\r
1772 //\r
1773 // Create the event for the DummyRcvToken.\r
1774 //\r
1775 Status = gBS->CreateEvent (\r
1776 EVT_NOTIFY_SIGNAL,\r
1777 TPL_NOTIFY,\r
1778 IpIoDummyHandler,\r
1779 IpInfo,\r
1780 &Event\r
1781 );\r
1782 if (EFI_ERROR (Status)) {\r
1783 goto ReleaseIpChild;\r
1784 }\r
1785\r
1786 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1787 IpInfo->DummyRcvToken.Ip4Token.Event = Event;\r
1788 } else {\r
1789 IpInfo->DummyRcvToken.Ip6Token.Event = Event;\r
1790 }\r
1791\r
1792 //\r
1793 // Link this IpInfo into the IpIo.\r
1794 //\r
1795 InsertTailList (&IpIo->IpList, &IpInfo->Entry);\r
1796\r
1797 return IpInfo;\r
1798\r
1799ReleaseIpChild:\r
1800\r
1801 IpIoCloseProtocolDestroyIpChild (\r
1802 IpIo->Controller,\r
1803 IpIo->Image,\r
1804 IpInfo->ChildHandle,\r
1805 IpInfo->IpVersion\r
1806 );\r
1807\r
1808ReleaseIpInfo:\r
1809\r
1810 gBS->FreePool (IpInfo);\r
1811\r
1812 return NULL;\r
1813}\r
1814\r
1815\r
1816/**\r
1817 Configure the IP instance of this IpInfo and start the receiving if IpConfigData\r
1818 is not NULL.\r
1819\r
1820 If IpInfo is NULL, then ASSERT().\r
1821 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
1822\r
1823 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.\r
1824 @param[in, out] IpConfigData The IP configure data used to configure the IP\r
1825 instance, if NULL the IP instance is reset. If\r
1826 UseDefaultAddress is set to TRUE, and the configure\r
1827 operation succeeds, the default address information\r
1828 is written back in this IpConfigData.\r
1829\r
1830 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully\r
1831 or no need to reconfigure it.\r
1832 @retval Others Configuration fails.\r
1833\r
1834**/\r
1835EFI_STATUS\r
1836EFIAPI\r
1837IpIoConfigIp (\r
1838 IN OUT IP_IO_IP_INFO *IpInfo,\r
1839 IN OUT VOID *IpConfigData OPTIONAL\r
1840 )\r
1841{\r
1842 EFI_STATUS Status;\r
1843 IP_IO_IP_PROTOCOL Ip;\r
1844 UINT8 IpVersion;\r
1845 EFI_IP4_MODE_DATA Ip4ModeData;\r
1846 EFI_IP6_MODE_DATA Ip6ModeData;\r
1847\r
1848 ASSERT (IpInfo != NULL);\r
1849\r
1850 if (IpInfo->RefCnt > 1) {\r
1851 //\r
1852 // This IP instance is shared, don't reconfigure it until it has only one\r
1853 // consumer. Currently, only the tcp children cloned from their passive parent\r
1854 // will share the same IP. So this cases only happens while IpConfigData is NULL,\r
1855 // let the last consumer clean the IP instance.\r
1856 //\r
1857 return EFI_SUCCESS;\r
1858 }\r
1859\r
1860 IpVersion = IpInfo->IpVersion;\r
1861 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1862\r
1863 Ip = IpInfo->Ip;\r
1864\r
1865 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1866 Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);\r
1867 } else {\r
1868 Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);\r
1869 }\r
1870\r
1871 if (EFI_ERROR (Status)) {\r
1872 return Status;\r
1873 }\r
1874\r
1875 if (IpConfigData != NULL) {\r
1876 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1877\r
1878 if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {\r
1879 Status = Ip.Ip4->GetModeData (\r
1880 Ip.Ip4,\r
1881 &Ip4ModeData,\r
1882 NULL,\r
1883 NULL\r
1884 );\r
1885 if (EFI_ERROR (Status)) {\r
1886 Ip.Ip4->Configure (Ip.Ip4, NULL);\r
1887 return Status;\r
1888 }\r
1889\r
1890 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);\r
1891 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);\r
1892 }\r
1893\r
1894 CopyMem (\r
1895 &IpInfo->Addr.Addr,\r
1896 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,\r
1897 sizeof (IP4_ADDR)\r
1898 );\r
1899 CopyMem (\r
1900 &IpInfo->PreMask.SubnetMask,\r
1901 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,\r
1902 sizeof (IP4_ADDR)\r
1903 );\r
1904\r
1905 Status = Ip.Ip4->Receive (\r
1906 Ip.Ip4,\r
1907 &IpInfo->DummyRcvToken.Ip4Token\r
1908 );\r
1909 if (EFI_ERROR (Status)) {\r
1910 Ip.Ip4->Configure (Ip.Ip4, NULL);\r
1911 }\r
1912 } else {\r
1913 Status = Ip.Ip6->GetModeData (\r
1914 Ip.Ip6,\r
1915 &Ip6ModeData,\r
1916 NULL,\r
1917 NULL\r
1918 );\r
1919 if (EFI_ERROR (Status)) {\r
1920 Ip.Ip6->Configure (Ip.Ip6, NULL);\r
1921 return Status;\r
1922 }\r
1923\r
1924 if (Ip6ModeData.IsConfigured) {\r
1925 CopyMem (\r
1926 &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,\r
1927 &Ip6ModeData.ConfigData.StationAddress,\r
1928 sizeof (EFI_IPv6_ADDRESS)\r
1929 );\r
1930\r
1931 if (Ip6ModeData.AddressList != NULL) {\r
1932 FreePool (Ip6ModeData.AddressList);\r
1933 }\r
1934\r
1935 if (Ip6ModeData.GroupTable != NULL) {\r
1936 FreePool (Ip6ModeData.GroupTable);\r
1937 }\r
1938\r
1939 if (Ip6ModeData.RouteTable != NULL) {\r
1940 FreePool (Ip6ModeData.RouteTable);\r
1941 }\r
1942\r
1943 if (Ip6ModeData.NeighborCache != NULL) {\r
1944 FreePool (Ip6ModeData.NeighborCache);\r
1945 }\r
1946\r
1947 if (Ip6ModeData.PrefixTable != NULL) {\r
1948 FreePool (Ip6ModeData.PrefixTable);\r
1949 }\r
1950\r
1951 if (Ip6ModeData.IcmpTypeList != NULL) {\r
1952 FreePool (Ip6ModeData.IcmpTypeList);\r
1953 }\r
1954\r
1955 } else {\r
1956 Status = EFI_NO_MAPPING;\r
1957 return Status;\r
1958 }\r
1959\r
1960 CopyMem (\r
1961 &IpInfo->Addr,\r
1962 &Ip6ModeData.ConfigData.StationAddress,\r
1963 sizeof (EFI_IPv6_ADDRESS)\r
1964 );\r
1965\r
1966 Status = Ip.Ip6->Receive (\r
1967 Ip.Ip6,\r
1968 &IpInfo->DummyRcvToken.Ip6Token\r
1969 );\r
1970 if (EFI_ERROR (Status)) {\r
1971 Ip.Ip6->Configure (Ip.Ip6, NULL);\r
1972 }\r
1973 }\r
1974 } else {\r
1975 //\r
1976 // The IP instance is reset, set the stored Addr and SubnetMask to zero.\r
1977 //\r
1978 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1979 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
1980 }\r
1981\r
1982 return Status;\r
1983}\r
1984\r
1985\r
1986/**\r
1987 Destroy an IP instance maintained in IpIo->IpList for\r
1988 sending purpose.\r
1989\r
1990 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().\r
1991\r
1992 This function pairs with IpIoAddIp(). The IpInfo is previously created by\r
1993 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance\r
1994 will be dstroyed if the RefCnt is zero.\r
1995\r
1996 @param[in] IpIo Pointer to the IP_IO instance.\r
1997 @param[in] IpInfo Pointer to the IpInfo to be removed.\r
1998\r
1999**/\r
2000VOID\r
2001EFIAPI\r
2002IpIoRemoveIp (\r
2003 IN IP_IO *IpIo,\r
2004 IN IP_IO_IP_INFO *IpInfo\r
2005 )\r
2006{\r
2007\r
2008 UINT8 IpVersion;\r
2009\r
2010 if (IpIo == NULL || IpInfo == NULL) {\r
2011 return;\r
2012 }\r
2013\r
2014 ASSERT (IpInfo->RefCnt > 0);\r
2015\r
2016 NET_PUT_REF (IpInfo);\r
2017\r
2018 if (IpInfo->RefCnt > 0) {\r
2019\r
2020 return;\r
2021 }\r
2022\r
2023 IpVersion = IpIo->IpVersion;\r
2024\r
2025 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
2026\r
2027 RemoveEntryList (&IpInfo->Entry);\r
2028\r
2029 if (IpVersion == IP_VERSION_4){\r
2030 IpInfo->Ip.Ip4->Configure (\r
2031 IpInfo->Ip.Ip4,\r
2032 NULL\r
2033 );\r
2034 IpIoCloseProtocolDestroyIpChild (\r
2035 IpIo->Controller,\r
2036 IpIo->Image,\r
2037 IpInfo->ChildHandle,\r
2038 IP_VERSION_4\r
2039 );\r
2040\r
2041 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);\r
2042\r
2043 } else {\r
2044\r
2045 IpInfo->Ip.Ip6->Configure (\r
2046 IpInfo->Ip.Ip6,\r
2047 NULL\r
2048 );\r
2049\r
2050 IpIoCloseProtocolDestroyIpChild (\r
2051 IpIo->Controller,\r
2052 IpIo->Image,\r
2053 IpInfo->ChildHandle,\r
2054 IP_VERSION_6\r
2055 );\r
2056\r
2057 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);\r
2058 }\r
2059\r
2060 FreePool (IpInfo);\r
2061}\r
2062\r
2063\r
2064/**\r
2065 Find the first IP protocol maintained in IpIo whose local\r
2066 address is the same as Src.\r
2067\r
2068 This function is called when the caller needs the IpIo to send data to the\r
2069 specified Src. The IpIo was added previously by IpIoAddIp().\r
2070\r
2071 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.\r
2072 @param[in] IpVersion The version of the IP protocol to use, either\r
2073 IPv4 or IPv6.\r
2074 @param[in] Src The local IP address.\r
2075\r
2076 @return Pointer to the IP protocol can be used for sending purpose and its local\r
2077 address is the same with Src. NULL if failed.\r
2078\r
2079**/\r
2080IP_IO_IP_INFO *\r
2081EFIAPI\r
2082IpIoFindSender (\r
2083 IN OUT IP_IO **IpIo,\r
2084 IN UINT8 IpVersion,\r
2085 IN EFI_IP_ADDRESS *Src\r
2086 )\r
2087{\r
2088 LIST_ENTRY *IpIoEntry;\r
2089 IP_IO *IpIoPtr;\r
2090 LIST_ENTRY *IpInfoEntry;\r
2091 IP_IO_IP_INFO *IpInfo;\r
2092\r
2093 if (IpIo == NULL || Src == NULL) {\r
2094 return NULL;\r
2095 }\r
2096\r
2097 if ((IpVersion != IP_VERSION_4) && (IpVersion != IP_VERSION_6)) {\r
2098 return NULL;\r
2099 }\r
2100\r
2101 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {\r
2102 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);\r
2103\r
2104 if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {\r
2105 continue;\r
2106 }\r
2107\r
2108 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {\r
2109 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);\r
2110 if (IpInfo->IpVersion == IP_VERSION_4){\r
2111\r
2112 if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {\r
2113 *IpIo = IpIoPtr;\r
2114 return IpInfo;\r
2115 }\r
2116\r
2117 } else {\r
2118\r
2119 if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {\r
2120 *IpIo = IpIoPtr;\r
2121 return IpInfo;\r
2122 }\r
2123 }\r
2124 }\r
2125 }\r
2126\r
2127 //\r
2128 // No match.\r
2129 //\r
2130 return NULL;\r
2131}\r
2132\r
2133\r
2134/**\r
2135 Get the ICMP error map information.\r
2136\r
2137 The ErrorStatus will be returned. The IsHard and Notify are optional. If they\r
2138 are not NULL, this routine will fill them.\r
2139\r
2140 @param[in] IcmpError IcmpError Type.\r
2141 @param[in] IpVersion The version of the IP protocol to use,\r
2142 either IPv4 or IPv6.\r
2143 @param[out] IsHard If TRUE, indicates that it is a hard error.\r
2144 @param[out] Notify If TRUE, SockError needs to be notified.\r
2145\r
2146 @retval EFI_UNSUPPORTED Unrecognizable ICMP error code.\r
2147 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.\r
2148\r
2149**/\r
2150EFI_STATUS\r
2151EFIAPI\r
2152IpIoGetIcmpErrStatus (\r
2153 IN UINT8 IcmpError,\r
2154 IN UINT8 IpVersion,\r
2155 OUT BOOLEAN *IsHard OPTIONAL,\r
2156 OUT BOOLEAN *Notify OPTIONAL\r
2157 )\r
2158{\r
2159 if (IpVersion == IP_VERSION_4 ) {\r
2160 ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);\r
2161\r
2162 if (IsHard != NULL) {\r
2163 *IsHard = mIcmpErrMap[IcmpError].IsHard;\r
2164 }\r
2165\r
2166 if (Notify != NULL) {\r
2167 *Notify = mIcmpErrMap[IcmpError].Notify;\r
2168 }\r
2169\r
2170 switch (IcmpError) {\r
2171 case ICMP_ERR_UNREACH_NET:\r
2172 return EFI_NETWORK_UNREACHABLE;\r
2173\r
2174 case ICMP_ERR_TIMXCEED_INTRANS:\r
2175 case ICMP_ERR_TIMXCEED_REASS:\r
2176 case ICMP_ERR_UNREACH_HOST:\r
2177 return EFI_HOST_UNREACHABLE;\r
2178\r
2179 case ICMP_ERR_UNREACH_PROTOCOL:\r
2180 return EFI_PROTOCOL_UNREACHABLE;\r
2181\r
2182 case ICMP_ERR_UNREACH_PORT:\r
2183 return EFI_PORT_UNREACHABLE;\r
2184\r
2185 case ICMP_ERR_MSGSIZE:\r
2186 case ICMP_ERR_UNREACH_SRCFAIL:\r
2187 case ICMP_ERR_QUENCH:\r
2188 case ICMP_ERR_PARAMPROB:\r
2189 return EFI_ICMP_ERROR;\r
2190\r
2191 default:\r
2192 ASSERT (FALSE);\r
2193 return EFI_UNSUPPORTED;\r
2194 }\r
2195\r
2196 } else if (IpVersion == IP_VERSION_6) {\r
2197\r
2198 ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);\r
2199\r
2200 if (IsHard != NULL) {\r
2201 *IsHard = mIcmp6ErrMap[IcmpError].IsHard;\r
2202 }\r
2203\r
2204 if (Notify != NULL) {\r
2205 *Notify = mIcmp6ErrMap[IcmpError].Notify;\r
2206 }\r
2207\r
2208 switch (IcmpError) {\r
2209 case ICMP6_ERR_UNREACH_NET:\r
2210 return EFI_NETWORK_UNREACHABLE;\r
2211\r
2212 case ICMP6_ERR_UNREACH_HOST:\r
2213 case ICMP6_ERR_TIMXCEED_HOPLIMIT:\r
2214 case ICMP6_ERR_TIMXCEED_REASS:\r
2215 return EFI_HOST_UNREACHABLE;\r
2216\r
2217 case ICMP6_ERR_UNREACH_PROTOCOL:\r
2218 return EFI_PROTOCOL_UNREACHABLE;\r
2219\r
2220 case ICMP6_ERR_UNREACH_PORT:\r
2221 return EFI_PORT_UNREACHABLE;\r
2222\r
2223 case ICMP6_ERR_PACKAGE_TOOBIG:\r
2224 case ICMP6_ERR_PARAMPROB_HEADER:\r
2225 case ICMP6_ERR_PARAMPROB_NEXHEADER:\r
2226 case ICMP6_ERR_PARAMPROB_IPV6OPTION:\r
2227 return EFI_ICMP_ERROR;\r
2228\r
2229 default:\r
2230 ASSERT (FALSE);\r
2231 return EFI_UNSUPPORTED;\r
2232 }\r
2233\r
2234 } else {\r
2235 //\r
2236 // Should never be here\r
2237 //\r
2238 ASSERT (FALSE);\r
2239 return EFI_UNSUPPORTED;\r
2240 }\r
2241}\r
2242\r
2243\r
2244/**\r
2245 Refresh the remote peer's Neighbor Cache entries.\r
2246\r
2247 This function is called when the caller needs the IpIo to refresh the existing\r
2248 IPv6 neighbor cache entries since the neighbor is considered reachable by the\r
2249 node has recently received a confirmation that packets sent recently to the\r
2250 neighbor were received by its IP layer.\r
2251\r
2252 @param[in] IpIo Pointer to an IP_IO instance\r
2253 @param[in] Neighbor The IP address of the neighbor\r
2254 @param[in] Timeout Time in 100-ns units that this entry will\r
2255 remain in the neighbor cache. A value of\r
2256 zero means that the entry is permanent.\r
2257 A value of non-zero means that the entry is\r
2258 dynamic and will be deleted after Timeout.\r
2259\r
2260 @retval EFI_SUCCESS The operation is completed successfully.\r
2261 @retval EFI_NOT_STARTED The IpIo is not configured.\r
2262 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.\r
2263 @retval EFI_NOT_FOUND The neighbor cache entry is not in the\r
2264 neighbor table.\r
2265 @retval EFI_UNSUPPORTED IP version is IPv4, which doesn't support neighbor cache refresh.\r
2266 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
2267\r
2268**/\r
2269EFI_STATUS\r
2270EFIAPI\r
2271IpIoRefreshNeighbor (\r
2272 IN IP_IO *IpIo,\r
2273 IN EFI_IP_ADDRESS *Neighbor,\r
2274 IN UINT32 Timeout\r
2275 )\r
2276{\r
2277 EFI_IP6_PROTOCOL *Ip;\r
2278\r
2279 if (!IpIo->IsConfigured) {\r
2280 return EFI_NOT_STARTED;\r
2281 }\r
2282\r
2283 if (IpIo->IpVersion != IP_VERSION_6) {\r
2284 return EFI_UNSUPPORTED;\r
2285 }\r
2286\r
2287 Ip = IpIo->Ip.Ip6;\r
2288\r
2289 return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);\r
2290}\r
2291\r