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