]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
Code clean up in NetLib:
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
CommitLineData
cbf316f2 1/** @file\r
6aac5e5f 2 IpIo Library.\r
cbf316f2 3\r
fb115c61 4Copyright (c) 2005 - 2009, Intel Corporation.<BR>\r
cbf316f2 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
cbf316f2 12**/\r
13\r
6aac5e5f 14#include <Uefi.h>\r
cbf316f2 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
752ef5d8 21#include <Library/BaseMemoryLib.h>\r
cbf316f2 22#include <Library/UefiBootServicesTableLib.h>\r
752ef5d8 23#include <Library/MemoryAllocationLib.h>\r
d8d26fb2 24#include <Library/DpcLib.h>\r
cbf316f2 25\r
cbf316f2 26\r
1204fe83 27GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList = {\r
cbf316f2 28 &mActiveIpIoList,\r
29 &mActiveIpIoList\r
30};\r
31\r
1204fe83 32GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData = {\r
cbf316f2 33 EFI_IP_PROTO_UDP,\r
34 FALSE,\r
35 TRUE,\r
36 FALSE,\r
37 FALSE,\r
38 FALSE,\r
84b5c78e 39 {{0, 0, 0, 0}},\r
40 {{0, 0, 0, 0}},\r
cbf316f2 41 0,\r
42 255,\r
43 FALSE,\r
44 FALSE,\r
45 0,\r
46 0\r
47};\r
48\r
1204fe83 49GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData = {\r
fb115c61 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
1204fe83 63GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap[10] = {\r
3cf888f5 64 {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET\r
65 {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST\r
66 {TRUE, TRUE }, // ICMP_ERR_UNREACH_PROTOCOL\r
67 {TRUE, TRUE }, // ICMP_ERR_UNREACH_PORT\r
68 {TRUE, TRUE }, // ICMP_ERR_MSGSIZE\r
69 {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL\r
70 {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS\r
71 {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS\r
72 {FALSE, FALSE}, // ICMP_ERR_QUENCH\r
73 {FALSE, TRUE } // ICMP_ERR_PARAMPROB\r
fb115c61 74};\r
75\r
1204fe83 76GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap[10] = {\r
3cf888f5 77 {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET\r
78 {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST\r
79 {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL\r
80 {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PORT \r
81 {TRUE, TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG\r
82 {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT\r
83 {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS\r
84 {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER \r
85 {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER\r
86 {FALSE, TRUE} // ICMP6_ERR_PARAMPROB_IPV6OPTION\r
01750eb0 87};\r
88\r
6aac5e5f 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
36ee91ca 96VOID\r
97EFIAPI\r
98IpIoTransmitHandlerDpc (\r
99 IN VOID *Context\r
100 );\r
101\r
6aac5e5f 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
cbf316f2 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
6aac5e5f 119 This function create an IP child ,open the IP protocol, and return the opened\r
e6ff63a5 120 IP protocol as Interface.\r
cbf316f2 121\r
6aac5e5f 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
fb115c61 125 @param[in] IpVersion The version of the IP protocol to use, either\r
126 IPv4 or IPv6.\r
6aac5e5f 127 @param[out] Interface Pointer used to get the IP protocol interface.\r
cbf316f2 128\r
6aac5e5f 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
cbf316f2 132\r
133**/\r
cbf316f2 134EFI_STATUS\r
135IpIoCreateIpChildOpenProtocol (\r
136 IN EFI_HANDLE ControllerHandle,\r
137 IN EFI_HANDLE ImageHandle,\r
138 IN EFI_HANDLE *ChildHandle,\r
b45b45b2 139 IN UINT8 IpVersion,\r
cbf316f2 140 OUT VOID **Interface\r
141 )\r
142{\r
143 EFI_STATUS Status;\r
fb115c61 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
cbf316f2 156\r
157 //\r
6aac5e5f 158 // Create an IP child.\r
cbf316f2 159 //\r
160 Status = NetLibCreateServiceChild (\r
161 ControllerHandle,\r
162 ImageHandle,\r
fb115c61 163 ServiceBindingGuid,\r
cbf316f2 164 ChildHandle\r
165 );\r
166 if (EFI_ERROR (Status)) {\r
167 return Status;\r
168 }\r
169\r
170 //\r
6aac5e5f 171 // Open the IP protocol installed on the *ChildHandle.\r
cbf316f2 172 //\r
173 Status = gBS->OpenProtocol (\r
174 *ChildHandle,\r
fb115c61 175 IpProtocolGuid,\r
cbf316f2 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
6aac5e5f 183 // On failure, destroy the IP child.\r
cbf316f2 184 //\r
185 NetLibDestroyServiceChild (\r
186 ControllerHandle,\r
187 ImageHandle,\r
fb115c61 188 ServiceBindingGuid,\r
cbf316f2 189 *ChildHandle\r
190 );\r
191 }\r
192\r
193 return Status;\r
194}\r
195\r
196\r
197/**\r
e6ff63a5 198 This function close the previously openned IP protocol and destroy the IP child.\r
cbf316f2 199\r
6aac5e5f 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
fb115c61 203 @param[in] IpVersion The version of the IP protocol to use, either\r
204 IPv4 or IPv6.\r
cbf316f2 205\r
6aac5e5f 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
cbf316f2 209\r
210**/\r
cbf316f2 211EFI_STATUS\r
212IpIoCloseProtocolDestroyIpChild (\r
213 IN EFI_HANDLE ControllerHandle,\r
214 IN EFI_HANDLE ImageHandle,\r
fb115c61 215 IN EFI_HANDLE ChildHandle,\r
b45b45b2 216 IN UINT8 IpVersion\r
cbf316f2 217 )\r
218{\r
219 EFI_STATUS Status;\r
fb115c61 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
cbf316f2 232\r
233 //\r
6aac5e5f 234 // Close the previously openned IP protocol.\r
cbf316f2 235 //\r
236 gBS->CloseProtocol (\r
237 ChildHandle,\r
fb115c61 238 IpProtocolGuid,\r
cbf316f2 239 ImageHandle,\r
240 ControllerHandle\r
241 );\r
242\r
243 //\r
6aac5e5f 244 // Destroy the IP child.\r
cbf316f2 245 //\r
246 Status = NetLibDestroyServiceChild (\r
247 ControllerHandle,\r
248 ImageHandle,\r
fb115c61 249 ServiceBindingGuid,\r
cbf316f2 250 ChildHandle\r
251 );\r
252\r
253 return Status;\r
254}\r
255\r
cbf316f2 256/**\r
fb115c61 257 This function handles ICMPv4 packets. It is the worker function of \r
258 IpIoIcmpHandler.\r
cbf316f2 259\r
fb115c61 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
cbf316f2 263\r
fb115c61 264 @retval EFI_SUCCESS The ICMPv4 packet is handled successfully.\r
265 @retval EFI_ABORTED This type of ICMPv4 packet is not supported.\r
cbf316f2 266\r
267**/\r
cbf316f2 268EFI_STATUS\r
fb115c61 269IpIoIcmpv4Handler (\r
6aac5e5f 270 IN IP_IO *IpIo,\r
271 IN OUT NET_BUF *Pkt,\r
272 IN EFI_NET_SESSION_DATA *Session\r
cbf316f2 273 )\r
274{\r
275 IP4_ICMP_ERROR_HEAD *IcmpHdr;\r
276 EFI_IP4_HEADER *IpHdr;\r
b45b45b2 277 UINT8 IcmpErr;\r
cbf316f2 278 UINT8 *PayLoadHdr;\r
279 UINT8 Type;\r
280 UINT8 Code;\r
281 UINT32 TrimBytes;\r
282\r
fb115c61 283 ASSERT (IpIo->IpVersion == IP_VERSION_4);\r
284\r
cbf316f2 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
b45b45b2 310 IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code);\r
cbf316f2 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
cbf316f2 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
b45b45b2 345 IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS);\r
cbf316f2 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
cbf316f2 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
fb115c61 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
b45b45b2 406 UINT8 IcmpErr;\r
fb115c61 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
b45b45b2 473 IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code);\r
fb115c61 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
b45b45b2 482 IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code);\r
fb115c61 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
b45b45b2 541 IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);\r
fb115c61 542\r
cbf316f2 543 return EFI_SUCCESS;\r
544}\r
545\r
fb115c61 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
cbf316f2 580\r
581/**\r
e6ff63a5 582 Free function for receive token of IP_IO. It is used to\r
cbf316f2 583 signal the recycle event to notify IP to recycle the\r
584 data buffer.\r
585\r
6aac5e5f 586 @param[in] Event The event to be signaled.\r
cbf316f2 587\r
cbf316f2 588**/\r
cbf316f2 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
6aac5e5f 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
cbf316f2 609\r
610 @return Pointer to the data structure created to wrap the packet. If NULL,\r
6aac5e5f 611 @return resource limit occurred.\r
cbf316f2 612\r
613**/\r
cbf316f2 614IP_IO_SEND_ENTRY *\r
615IpIoCreateSndEntry (\r
6aac5e5f 616 IN OUT IP_IO *IpIo,\r
617 IN OUT NET_BUF *Pkt,\r
fb115c61 618 IN VOID *Sender,\r
6aac5e5f 619 IN VOID *Context OPTIONAL,\r
620 IN VOID *NotifyData OPTIONAL,\r
fb115c61 621 IN EFI_IP_ADDRESS *Dest OPTIONAL,\r
6aac5e5f 622 IN IP_IO_OVERRIDE *Override\r
cbf316f2 623 )\r
624{\r
625 IP_IO_SEND_ENTRY *SndEntry;\r
fb115c61 626 EFI_EVENT Event; \r
cbf316f2 627 EFI_STATUS Status;\r
fb115c61 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
cbf316f2 642\r
643 //\r
644 // Allocate resource for SndEntry\r
645 //\r
e48e37fc 646 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));\r
cbf316f2 647 if (NULL == SndEntry) {\r
648 return NULL;\r
649 }\r
650\r
cbf316f2 651 Status = gBS->CreateEvent (\r
652 EVT_NOTIFY_SIGNAL,\r
e48e37fc 653 TPL_NOTIFY,\r
cbf316f2 654 IpIoTransmitHandler,\r
655 SndEntry,\r
fb115c61 656 &Event\r
cbf316f2 657 );\r
658 if (EFI_ERROR (Status)) {\r
fb115c61 659 goto ON_ERROR;\r
cbf316f2 660 }\r
661\r
fb115c61 662 FragmentCount = Pkt->BlockOpNum;\r
663\r
cbf316f2 664 //\r
665 // Allocate resource for TxData\r
666 //\r
fb115c61 667 TxData = (IP_IO_IP_TX_DATA *) AllocatePool (\r
668 sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)\r
cbf316f2 669 );\r
670\r
671 if (NULL == TxData) {\r
fb115c61 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
cbf316f2 682 }\r
683\r
fb115c61 684 NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);\r
685\r
686\r
cbf316f2 687 //\r
688 // Allocate resource for OverrideData if needed\r
689 //\r
cbf316f2 690 if (NULL != Override) {\r
691\r
fb115c61 692 OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);\r
cbf316f2 693 if (NULL == OverrideData) {\r
fb115c61 694 goto ON_ERROR;\r
cbf316f2 695 }\r
cbf316f2 696 }\r
697\r
698 //\r
fb115c61 699 // Set other fields of TxData except the fragment table\r
cbf316f2 700 //\r
fb115c61 701 if (IpIo->IpVersion == IP_VERSION_4) {\r
cbf316f2 702\r
fb115c61 703 Ip4TxData = &TxData->Ip4TxData;\r
cbf316f2 704\r
fb115c61 705 CopyMem (&Ip4TxData->DestinationAddress, Dest, sizeof (EFI_IPv4_ADDRESS));\r
cbf316f2 706\r
fb115c61 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
cbf316f2 740\r
741 //\r
742 // Set the fields of SndEntry\r
743 //\r
744 SndEntry->IpIo = IpIo;\r
6aac5e5f 745 SndEntry->Ip = Sender;\r
cbf316f2 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
e48e37fc 752 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);\r
cbf316f2 753\r
754 return SndEntry;\r
755\r
fb115c61 756ON_ERROR:\r
757\r
758 if (OverrideData != NULL) {\r
759 FreePool (OverrideData);\r
760 }\r
cbf316f2 761\r
fb115c61 762 if (TxData != NULL) {\r
763 FreePool (TxData);\r
764 }\r
cbf316f2 765\r
fb115c61 766 if (SndEntry != NULL) {\r
767 FreePool (SndEntry);\r
768 }\r
cbf316f2 769\r
fb115c61 770 if (Event != NULL) {\r
771 gBS->CloseEvent (Event);\r
772 }\r
cbf316f2 773\r
774 return NULL;\r
775}\r
776\r
777\r
778/**\r
779 Destroy the SndEntry.\r
e6ff63a5 780 \r
781 This function pairs with IpIoCreateSndEntry().\r
cbf316f2 782\r
6aac5e5f 783 @param[in] SndEntry Pointer to the send entry to be destroyed.\r
cbf316f2 784\r
cbf316f2 785**/\r
cbf316f2 786VOID\r
787IpIoDestroySndEntry (\r
788 IN IP_IO_SEND_ENTRY *SndEntry\r
789 )\r
790{\r
fb115c61 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
cbf316f2 806\r
fb115c61 807 gBS->CloseEvent (Event);\r
cbf316f2 808\r
fb115c61 809 FreePool (TxData);\r
810\r
811 if (NULL != Override) {\r
812 FreePool (Override);\r
cbf316f2 813 }\r
814\r
cbf316f2 815 NetbufFree (SndEntry->Pkt);\r
cbf316f2 816\r
e48e37fc 817 RemoveEntryList (&SndEntry->Entry);\r
cbf316f2 818\r
fb115c61 819 FreePool (SndEntry);\r
cbf316f2 820}\r
821\r
822\r
823/**\r
824 Notify function for IP transmit token.\r
825\r
6aac5e5f 826 @param[in] Context The context passed in by the event notifier.\r
cbf316f2 827\r
cbf316f2 828**/\r
cbf316f2 829VOID\r
830EFIAPI\r
36ee91ca 831IpIoTransmitHandlerDpc (\r
cbf316f2 832 IN VOID *Context\r
833 )\r
834{\r
835 IP_IO *IpIo;\r
836 IP_IO_SEND_ENTRY *SndEntry;\r
fb115c61 837 EFI_STATUS Status;\r
cbf316f2 838\r
839 SndEntry = (IP_IO_SEND_ENTRY *) Context;\r
840\r
841 IpIo = SndEntry->IpIo;\r
842\r
fb115c61 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
8de75da2 851 if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {\r
cbf316f2 852 IpIo->PktSentNotify (\r
fb115c61 853 Status,\r
cbf316f2 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
6aac5e5f 863\r
36ee91ca 864/**\r
865 Notify function for IP transmit token.\r
866\r
6aac5e5f 867 @param[in] Event The event signaled.\r
868 @param[in] Context The context passed in by the event notifier.\r
36ee91ca 869\r
36ee91ca 870**/\r
36ee91ca 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
d8d26fb2 881 QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);\r
36ee91ca 882}\r
883\r
cbf316f2 884\r
885/**\r
886 The dummy handler for the dummy IP receive token.\r
887\r
6aac5e5f 888 @param[in] Context The context passed in by the event notifier.\r
cbf316f2 889\r
cbf316f2 890**/\r
cbf316f2 891VOID\r
892EFIAPI\r
36ee91ca 893IpIoDummyHandlerDpc (\r
cbf316f2 894 IN VOID *Context\r
895 )\r
896{\r
897 IP_IO_IP_INFO *IpInfo;\r
fb115c61 898 EFI_STATUS Status;\r
899 EFI_EVENT RecycleEvent;\r
cbf316f2 900\r
cbf316f2 901 IpInfo = (IP_IO_IP_INFO *) Context;\r
cbf316f2 902\r
fb115c61 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
36ee91ca 926 //\r
927 // The reception is actively aborted by the consumer, directly return.\r
928 //\r
929 return;\r
fb115c61 930 } else if (EFI_SUCCESS == Status) {\r
931 //\r
932 // Recycle the RxData.\r
933 //\r
934 ASSERT (RecycleEvent != NULL);\r
cbf316f2 935\r
fb115c61 936 gBS->SignalEvent (RecycleEvent);\r
cbf316f2 937 }\r
938\r
fb115c61 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
cbf316f2 953}\r
954\r
955\r
956/**\r
6aac5e5f 957 This function add IpIoDummyHandlerDpc to the end of the DPC queue.\r
cbf316f2 958\r
6aac5e5f 959 @param[in] Event The event signaled.\r
960 @param[in] Context The context passed in by the event notifier.\r
cbf316f2 961\r
cbf316f2 962**/\r
cbf316f2 963VOID\r
964EFIAPI\r
36ee91ca 965IpIoDummyHandler (\r
cbf316f2 966 IN EFI_EVENT Event,\r
967 IN VOID *Context\r
968 )\r
36ee91ca 969{\r
970 //\r
971 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK\r
972 //\r
d8d26fb2 973 QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);\r
36ee91ca 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
6aac5e5f 981 @param[in] Context The context passed in by the event notifier.\r
36ee91ca 982\r
36ee91ca 983**/\r
36ee91ca 984VOID\r
985EFIAPI\r
986IpIoListenHandlerDpc (\r
987 IN VOID *Context\r
988 )\r
cbf316f2 989{\r
990 IP_IO *IpIo;\r
991 EFI_STATUS Status;\r
fb115c61 992 IP_IO_IP_RX_DATA *RxData;\r
993 VOID *Ip;\r
cbf316f2 994 EFI_NET_SESSION_DATA Session;\r
995 NET_BUF *Pkt;\r
996\r
fb115c61 997 IpIo = (IP_IO *) Context;\r
998 Ip = IpIo->Ip;\r
cbf316f2 999\r
fb115c61 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
cbf316f2 1009\r
36ee91ca 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
cbf316f2 1017 if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {\r
1018 //\r
6aac5e5f 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
cbf316f2 1022 //\r
1023 goto Resume;\r
1024 }\r
1025\r
1026 if (NULL == IpIo->PktRcvdNotify) {\r
1027 goto CleanUp;\r
1028 }\r
1029\r
fb115c61 1030 if (IpIo->IpVersion == IP_VERSION_4) {\r
1031 if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&\r
f6b7393c 1032 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), 0)) {\r
cbf316f2 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
fb115c61 1040 // Create a netbuffer representing IPv4 packet\r
cbf316f2 1041 //\r
1042 Pkt = NetbufFromExt (\r
fb115c61 1043 (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,\r
1044 RxData->Ip4RxData.FragmentCount,\r
cbf316f2 1045 0,\r
1046 0,\r
1047 IpIoExtFree,\r
fb115c61 1048 RxData->Ip4RxData.RecycleSignal\r
cbf316f2 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
fb115c61 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
a09ee46d 1060 Session.IpHdrLen = RxData->Ip4RxData.HeaderLength;\r
fb115c61 1061 Session.IpVersion = IP_VERSION_4;\r
1062 } else {\r
1063\r
f6b7393c 1064 if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {\r
fb115c61 1065 goto CleanUp;\r
1066 }\r
1067 \r
1068 //\r
1069 // Create a netbuffer representing IPv6 packet\r
1070 //\r
1071 Pkt = NetbufFromExt (\r
1072 (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,\r
1073 RxData->Ip6RxData.FragmentCount,\r
1074 0,\r
1075 0,\r
1076 IpIoExtFree,\r
1077 RxData->Ip6RxData.RecycleSignal\r
1078 );\r
1079 if (NULL == Pkt) {\r
1080 goto CleanUp;\r
1081 }\r
1082\r
1083 //\r
1084 // Create a net session\r
1085 //\r
1086 CopyMem (\r
1087 &Session.Source, \r
1088 &RxData->Ip6RxData.Header->SourceAddress,\r
1089 sizeof(EFI_IPv6_ADDRESS)\r
1090 );\r
1091 CopyMem (\r
1092 &Session.Dest, \r
1093 &RxData->Ip6RxData.Header->DestinationAddress, \r
1094 sizeof(EFI_IPv6_ADDRESS)\r
1095 );\r
1096 Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;\r
a09ee46d 1097 Session.IpHdrLen = RxData->Ip6RxData.HeaderLength;\r
fb115c61 1098 Session.IpVersion = IP_VERSION_6;\r
1099 } \r
cbf316f2 1100\r
1101 if (EFI_SUCCESS == Status) {\r
1102\r
b45b45b2 1103 IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);\r
cbf316f2 1104 } else {\r
1105 //\r
1106 // Status is EFI_ICMP_ERROR\r
1107 //\r
1108 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);\r
1109 if (EFI_ERROR (Status)) {\r
1110 NetbufFree (Pkt);\r
1111 }\r
1112 }\r
1113\r
1114 goto Resume;\r
1115\r
1116CleanUp:\r
fb115c61 1117\r
1118 if (IpIo->IpVersion == IP_VERSION_4){\r
1119 gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);\r
1120 } else {\r
1121 gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal); \r
1122 }\r
cbf316f2 1123\r
1124Resume:\r
cbf316f2 1125\r
fb115c61 1126 if (IpIo->IpVersion == IP_VERSION_4){\r
1127 ((EFI_IP4_PROTOCOL *) Ip)->Receive (Ip, &(IpIo->RcvToken.Ip4Token));\r
1128 } else {\r
1129 ((EFI_IP6_PROTOCOL *) Ip)->Receive (Ip, &(IpIo->RcvToken.Ip6Token));\r
1130 }\r
1131}\r
cbf316f2 1132\r
36ee91ca 1133/**\r
6aac5e5f 1134 This function add IpIoListenHandlerDpc to the end of the DPC queue.\r
36ee91ca 1135\r
6aac5e5f 1136 @param[in] Event The event signaled.\r
1137 @param[in] Context The context passed in by the event notifier.\r
36ee91ca 1138\r
1139**/\r
36ee91ca 1140VOID\r
1141EFIAPI\r
1142IpIoListenHandler (\r
1143 IN EFI_EVENT Event,\r
1144 IN VOID *Context\r
1145 )\r
1146{\r
1147 //\r
1148 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
1149 //\r
d8d26fb2 1150 QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);\r
36ee91ca 1151}\r
1152\r
1153\r
cbf316f2 1154/**\r
1155 Create a new IP_IO instance.\r
e6ff63a5 1156 \r
fb115c61 1157 This function uses IP4/IP6 service binding protocol in Controller to create\r
1158 an IP4/IP6 child (aka IP4/IP6 instance).\r
cbf316f2 1159\r
6aac5e5f 1160 @param[in] Image The image handle of the driver or application that\r
e6ff63a5 1161 consumes IP_IO.\r
fb115c61 1162 @param[in] Controller The controller handle that has IP4 or IP6 service\r
1163 binding protocol installed.\r
1164 @param[in] IpVersion The version of the IP protocol to use, either\r
1165 IPv4 or IPv6. \r
cbf316f2 1166\r
e6ff63a5 1167 @return Pointer to a newly created IP_IO instance, or NULL if failed.\r
cbf316f2 1168\r
1169**/\r
1170IP_IO *\r
7b414b4e 1171EFIAPI\r
cbf316f2 1172IpIoCreate (\r
1173 IN EFI_HANDLE Image,\r
fb115c61 1174 IN EFI_HANDLE Controller,\r
b45b45b2 1175 IN UINT8 IpVersion\r
cbf316f2 1176 )\r
1177{\r
1178 EFI_STATUS Status;\r
1179 IP_IO *IpIo;\r
fb115c61 1180 EFI_EVENT Event;\r
1181\r
1182 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
cbf316f2 1183\r
e48e37fc 1184 IpIo = AllocateZeroPool (sizeof (IP_IO));\r
cbf316f2 1185 if (NULL == IpIo) {\r
1186 return NULL;\r
1187 }\r
1188\r
e48e37fc 1189 InitializeListHead (&(IpIo->PendingSndList));\r
1190 InitializeListHead (&(IpIo->IpList));\r
cbf316f2 1191 IpIo->Controller = Controller;\r
1192 IpIo->Image = Image;\r
fb115c61 1193 IpIo->IpVersion = IpVersion;\r
1194 Event = NULL;\r
cbf316f2 1195\r
1196 Status = gBS->CreateEvent (\r
1197 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1198 TPL_NOTIFY,\r
cbf316f2 1199 IpIoListenHandler,\r
1200 IpIo,\r
fb115c61 1201 &Event\r
cbf316f2 1202 );\r
1203 if (EFI_ERROR (Status)) {\r
1204 goto ReleaseIpIo;\r
1205 }\r
1206\r
fb115c61 1207 if (IpVersion == IP_VERSION_4) {\r
1208 IpIo->RcvToken.Ip4Token.Event = Event;\r
1209 } else {\r
1210 IpIo->RcvToken.Ip6Token.Event = Event;\r
1211 }\r
1212\r
cbf316f2 1213 //\r
1214 // Create an IP child and open IP protocol\r
1215 //\r
1216 Status = IpIoCreateIpChildOpenProtocol (\r
1217 Controller,\r
1218 Image,\r
1219 &IpIo->ChildHandle,\r
fb115c61 1220 IpVersion, \r
cbf316f2 1221 (VOID **)&(IpIo->Ip)\r
1222 );\r
1223 if (EFI_ERROR (Status)) {\r
1224 goto ReleaseIpIo;\r
1225 }\r
1226\r
1227 return IpIo;\r
1228\r
1229ReleaseIpIo:\r
1230\r
fb115c61 1231 if (Event != NULL) {\r
1232 gBS->CloseEvent (Event);\r
cbf316f2 1233 }\r
1234\r
e48e37fc 1235 gBS->FreePool (IpIo);\r
cbf316f2 1236\r
1237 return NULL;\r
1238}\r
1239\r
1240\r
1241/**\r
1242 Open an IP_IO instance for use.\r
e6ff63a5 1243 \r
1244 This function is called after IpIoCreate(). It is used for configuring the IP\r
1245 instance and register the callbacks and their context data for sending and\r
1246 receiving IP packets.\r
cbf316f2 1247\r
6aac5e5f 1248 @param[in, out] IpIo Pointer to an IP_IO instance that needs\r
1249 to open.\r
1250 @param[in] OpenData The configuration data and callbacks for\r
1251 the IP_IO instance.\r
cbf316f2 1252\r
6aac5e5f 1253 @retval EFI_SUCCESS The IP_IO instance opened with OpenData\r
1254 successfully.\r
1255 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to \r
1256 reopen it.\r
1257 @retval Others Error condition occurred.\r
cbf316f2 1258\r
1259**/\r
1260EFI_STATUS\r
7b414b4e 1261EFIAPI\r
cbf316f2 1262IpIoOpen (\r
6aac5e5f 1263 IN OUT IP_IO *IpIo,\r
1264 IN IP_IO_OPEN_DATA *OpenData\r
cbf316f2 1265 )\r
1266{\r
1267 EFI_STATUS Status;\r
fb115c61 1268 VOID *Ip;\r
b45b45b2 1269 UINT8 IpVersion;\r
cbf316f2 1270\r
1271 if (IpIo->IsConfigured) {\r
1272 return EFI_ACCESS_DENIED;\r
1273 }\r
1274\r
fb115c61 1275 IpVersion = IpIo->IpVersion;\r
1276\r
1277 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1278\r
cbf316f2 1279 Ip = IpIo->Ip;\r
1280\r
1281 //\r
1282 // configure ip\r
1283 //\r
fb115c61 1284 if (IpVersion == IP_VERSION_4){\r
1285 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure (\r
1286 (EFI_IP4_PROTOCOL *) Ip,\r
1287 &OpenData->IpConfigData.Ip4CfgData\r
1288 );\r
1289 } else {\r
1290\r
1291 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure (\r
1292 (EFI_IP6_PROTOCOL *) Ip, \r
1293 &OpenData->IpConfigData.Ip6CfgData\r
1294 );\r
1295 }\r
1296\r
cbf316f2 1297 if (EFI_ERROR (Status)) {\r
1298 return Status;\r
1299 }\r
1300\r
1301 //\r
6aac5e5f 1302 // @bug To delete the default route entry in this Ip, if it is:\r
1303 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified\r
1304 // @bug its code\r
cbf316f2 1305 //\r
fb115c61 1306 if (IpVersion == IP_VERSION_4){\r
1307 Status = ((EFI_IP4_PROTOCOL *) Ip)->Routes (\r
1308 (EFI_IP4_PROTOCOL *) Ip,\r
1309 TRUE,\r
1310 &mZeroIp4Addr,\r
1311 &mZeroIp4Addr,\r
1312 &mZeroIp4Addr\r
1313 );\r
1314\r
1315 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {\r
1316 return Status;\r
1317 }\r
cbf316f2 1318 }\r
1319\r
1320 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;\r
1321 IpIo->PktSentNotify = OpenData->PktSentNotify;\r
1322\r
1323 IpIo->RcvdContext = OpenData->RcvdContext;\r
1324 IpIo->SndContext = OpenData->SndContext;\r
1325\r
fb115c61 1326 if (IpVersion == IP_VERSION_4){\r
1327 IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;\r
cbf316f2 1328\r
fb115c61 1329 //\r
1330 // start to listen incoming packet\r
1331 //\r
1332 Status = ((EFI_IP4_PROTOCOL *) Ip)->Receive (\r
1333 (EFI_IP4_PROTOCOL *) Ip,\r
1334 &(IpIo->RcvToken.Ip4Token)\r
1335 );\r
1336 if (EFI_ERROR (Status)) {\r
1337 ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, NULL);\r
1338 goto ErrorExit;\r
1339 }\r
1340\r
1341 } else {\r
1342\r
1343 IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;\r
1344 Status = ((EFI_IP6_PROTOCOL *) Ip)->Receive (\r
1345 (EFI_IP6_PROTOCOL *) Ip,\r
1346 &(IpIo->RcvToken.Ip6Token)\r
1347 );\r
1348 if (EFI_ERROR (Status)) {\r
1349 ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);\r
1350 goto ErrorExit;\r
1351 }\r
cbf316f2 1352 }\r
1353\r
1354 IpIo->IsConfigured = TRUE;\r
e48e37fc 1355 InsertTailList (&mActiveIpIoList, &IpIo->Entry);\r
cbf316f2 1356\r
1357ErrorExit:\r
1358\r
1359 return Status;\r
1360}\r
1361\r
1362\r
1363/**\r
1364 Stop an IP_IO instance.\r
e6ff63a5 1365 \r
1366 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all\r
1367 the pending send/receive tokens will be canceled.\r
cbf316f2 1368\r
6aac5e5f 1369 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.\r
cbf316f2 1370\r
6aac5e5f 1371 @retval EFI_SUCCESS The IP_IO instance stopped successfully.\r
1372 @retval Others Error condition occurred.\r
cbf316f2 1373\r
1374**/\r
1375EFI_STATUS\r
e6ff63a5 1376EFIAPI\r
cbf316f2 1377IpIoStop (\r
6aac5e5f 1378 IN OUT IP_IO *IpIo\r
cbf316f2 1379 )\r
1380{\r
1381 EFI_STATUS Status;\r
fb115c61 1382 VOID *Ip;\r
cbf316f2 1383 IP_IO_IP_INFO *IpInfo;\r
b45b45b2 1384 UINT8 IpVersion;\r
cbf316f2 1385\r
1386 if (!IpIo->IsConfigured) {\r
1387 return EFI_SUCCESS;\r
1388 }\r
1389\r
fb115c61 1390 IpVersion = IpIo->IpVersion;\r
1391\r
1392 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1393\r
cbf316f2 1394 //\r
1395 // Remove the IpIo from the active IpIo list.\r
1396 //\r
e48e37fc 1397 RemoveEntryList (&IpIo->Entry);\r
cbf316f2 1398\r
1399 Ip = IpIo->Ip;\r
1400\r
1401 //\r
1402 // Configure NULL Ip\r
1403 //\r
fb115c61 1404 if (IpVersion == IP_VERSION_4) {\r
1405 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, NULL);\r
1406 } else {\r
1407 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);\r
1408 }\r
cbf316f2 1409 if (EFI_ERROR (Status)) {\r
1410 return Status;\r
1411 }\r
1412\r
1413 IpIo->IsConfigured = FALSE;\r
1414\r
1415 //\r
1416 // Detroy the Ip List used by IpIo\r
1417 //\r
34edf2ae 1418\r
e48e37fc 1419 while (!IsListEmpty (&(IpIo->IpList))) {\r
cbf316f2 1420 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);\r
1421\r
1422 IpIoRemoveIp (IpIo, IpInfo);\r
1423 }\r
1424\r
1425 //\r
6aac5e5f 1426 // All pending send tokens should be flushed by reseting the IP instances.\r
cbf316f2 1427 //\r
e48e37fc 1428 ASSERT (IsListEmpty (&IpIo->PendingSndList));\r
cbf316f2 1429\r
1430 //\r
1431 // Close the receive event.\r
1432 //\r
fb115c61 1433 if (IpVersion == IP_VERSION_4){\r
1434 gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);\r
1435 } else {\r
1436 gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);\r
1437 }\r
cbf316f2 1438\r
1439 return EFI_SUCCESS;\r
1440}\r
1441\r
1442\r
1443/**\r
1444 Destroy an IP_IO instance.\r
e6ff63a5 1445 \r
1446 This function is paired with IpIoCreate(). The IP_IO will be closed first.\r
8f5e6151 1447 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().\r
cbf316f2 1448\r
6aac5e5f 1449 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be\r
e6ff63a5 1450 destroyed.\r
cbf316f2 1451\r
6aac5e5f 1452 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.\r
1453 @retval Others Error condition occurred.\r
cbf316f2 1454\r
1455**/\r
1456EFI_STATUS\r
7b414b4e 1457EFIAPI\r
cbf316f2 1458IpIoDestroy (\r
6aac5e5f 1459 IN OUT IP_IO *IpIo\r
cbf316f2 1460 )\r
1461{\r
1462 //\r
1463 // Stop the IpIo.\r
1464 //\r
1465 IpIoStop (IpIo);\r
1466\r
1467 //\r
1468 // Close the IP protocol and destroy the child.\r
1469 //\r
fb115c61 1470 IpIoCloseProtocolDestroyIpChild (\r
1471 IpIo->Controller,\r
1472 IpIo->Image,\r
1473 IpIo->ChildHandle,\r
1474 IpIo->IpVersion\r
1475 );\r
cbf316f2 1476\r
e48e37fc 1477 gBS->FreePool (IpIo);\r
cbf316f2 1478\r
1479 return EFI_SUCCESS;\r
1480}\r
1481\r
1482\r
1483/**\r
1484 Send out an IP packet.\r
e6ff63a5 1485 \r
1486 This function is called after IpIoOpen(). The data to be sent are wrapped in\r
1487 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be\r
1488 overriden by Sender. Other sending configs, like source address and gateway\r
1489 address etc., are specified in OverrideData.\r
cbf316f2 1490\r
6aac5e5f 1491 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP\r
1492 packet.\r
1493 @param[in, out] Pkt Pointer to the IP packet to be sent.\r
1494 @param[in] Sender The IP protocol instance used for sending.\r
8f5e6151 1495 @param[in] Context Optional context data.\r
1496 @param[in] NotifyData Optional notify data.\r
6aac5e5f 1497 @param[in] Dest The destination IP address to send this packet to.\r
1498 @param[in] OverrideData The data to override some configuration of the IP\r
1499 instance used for sending.\r
cbf316f2 1500\r
6aac5e5f 1501 @retval EFI_SUCCESS The operation is completed successfully.\r
1502 @retval EFI_NOT_STARTED The IpIo is not configured.\r
1503 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
cbf316f2 1504\r
1505**/\r
1506EFI_STATUS\r
7b414b4e 1507EFIAPI\r
cbf316f2 1508IpIoSend (\r
6aac5e5f 1509 IN OUT IP_IO *IpIo,\r
1510 IN OUT NET_BUF *Pkt,\r
1511 IN IP_IO_IP_INFO *Sender OPTIONAL,\r
1512 IN VOID *Context OPTIONAL,\r
1513 IN VOID *NotifyData OPTIONAL,\r
fb115c61 1514 IN EFI_IP_ADDRESS *Dest,\r
6aac5e5f 1515 IN IP_IO_OVERRIDE *OverrideData OPTIONAL\r
cbf316f2 1516 )\r
1517{\r
1518 EFI_STATUS Status;\r
fb115c61 1519 VOID *Ip;\r
cbf316f2 1520 IP_IO_SEND_ENTRY *SndEntry;\r
1521\r
fb115c61 1522 ASSERT ((IpIo->IpVersion != IP_VERSION_4) || (Dest != NULL));\r
1523\r
cbf316f2 1524 if (!IpIo->IsConfigured) {\r
1525 return EFI_NOT_STARTED;\r
1526 }\r
1527\r
1528 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;\r
1529\r
1530 //\r
1531 // create a new SndEntry\r
1532 //\r
1533 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);\r
1534 if (NULL == SndEntry) {\r
1535 return EFI_OUT_OF_RESOURCES;\r
1536 }\r
1537\r
1538 //\r
1539 // Send this Packet\r
1540 //\r
fb115c61 1541 if (IpIo->IpVersion == IP_VERSION_4){\r
1542 Status = ((EFI_IP4_PROTOCOL *) Ip)->Transmit (\r
1543 (EFI_IP4_PROTOCOL *) Ip,\r
1544 &SndEntry->SndToken.Ip4Token\r
1545 );\r
1546 } else {\r
1547 Status = ((EFI_IP6_PROTOCOL *) Ip)->Transmit (\r
1548 (EFI_IP6_PROTOCOL *) Ip,\r
1549 &SndEntry->SndToken.Ip6Token\r
1550 );\r
1551 }\r
1552\r
cbf316f2 1553 if (EFI_ERROR (Status)) {\r
1554 IpIoDestroySndEntry (SndEntry);\r
1555 }\r
1556\r
1557 return Status;\r
1558}\r
1559\r
1560\r
1561/**\r
1562 Cancel the IP transmit token which wraps this Packet.\r
1563\r
6aac5e5f 1564 @param[in] IpIo Pointer to the IP_IO instance.\r
1565 @param[in] Packet Pointer to the packet of NET_BUF to cancel.\r
cbf316f2 1566\r
1567**/\r
1568VOID\r
7b414b4e 1569EFIAPI\r
cbf316f2 1570IpIoCancelTxToken (\r
1571 IN IP_IO *IpIo,\r
1572 IN VOID *Packet\r
1573 )\r
1574{\r
e48e37fc 1575 LIST_ENTRY *Node;\r
cbf316f2 1576 IP_IO_SEND_ENTRY *SndEntry;\r
fb115c61 1577 VOID *Ip;\r
cbf316f2 1578\r
fb115c61 1579 ASSERT ((IpIo != NULL) && (Packet != NULL));\r
cbf316f2 1580\r
1581 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {\r
1582\r
1583 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);\r
1584\r
1585 if (SndEntry->Pkt == Packet) {\r
1586\r
1587 Ip = SndEntry->Ip;\r
fb115c61 1588\r
1589 if (IpIo->IpVersion == IP_VERSION_4) {\r
1590 ((EFI_IP4_PROTOCOL *) Ip)->Cancel (\r
1591 (EFI_IP4_PROTOCOL *) Ip,\r
1592 &SndEntry->SndToken.Ip4Token\r
1593 );\r
1594 } else {\r
1595 ((EFI_IP6_PROTOCOL *) Ip)->Cancel (\r
1596 (EFI_IP6_PROTOCOL *) Ip,\r
1597 &SndEntry->SndToken.Ip6Token\r
1598 );\r
1599 }\r
cbf316f2 1600\r
cbf316f2 1601 break;\r
1602 }\r
1603 }\r
1604\r
1605}\r
1606\r
1607\r
1608/**\r
1609 Add a new IP instance for sending data.\r
e6ff63a5 1610 \r
1611 The function is used to add the IP_IO to the IP_IO sending list. The caller\r
1612 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send\r
1613 data.\r
cbf316f2 1614\r
6aac5e5f 1615 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP\r
1616 instance for sending purpose.\r
cbf316f2 1617\r
e6ff63a5 1618 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.\r
cbf316f2 1619\r
1620**/\r
1621IP_IO_IP_INFO *\r
7b414b4e 1622EFIAPI\r
cbf316f2 1623IpIoAddIp (\r
6aac5e5f 1624 IN OUT IP_IO *IpIo\r
cbf316f2 1625 )\r
1626{\r
1627 EFI_STATUS Status;\r
1628 IP_IO_IP_INFO *IpInfo;\r
fb115c61 1629 EFI_EVENT Event;\r
cbf316f2 1630\r
6aac5e5f 1631 ASSERT (IpIo != NULL);\r
cbf316f2 1632\r
e48e37fc 1633 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));\r
cbf316f2 1634 if (IpInfo == NULL) {\r
fb115c61 1635 return NULL;\r
cbf316f2 1636 }\r
1637\r
1638 //\r
1639 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP\r
1640 // instance.\r
1641 //\r
e48e37fc 1642 InitializeListHead (&IpInfo->Entry);\r
cbf316f2 1643 IpInfo->ChildHandle = NULL;\r
fb115c61 1644 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1645 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
1646\r
1647 IpInfo->RefCnt = 1;\r
1648 IpInfo->IpVersion = IpIo->IpVersion;\r
cbf316f2 1649\r
1650 //\r
fb115c61 1651 // Create the IP instance and open the IP protocol.\r
cbf316f2 1652 //\r
1653 Status = IpIoCreateIpChildOpenProtocol (\r
1654 IpIo->Controller,\r
1655 IpIo->Image,\r
1656 &IpInfo->ChildHandle,\r
fb115c61 1657 IpInfo->IpVersion,\r
4eb65aff 1658 (VOID **) &IpInfo->Ip\r
cbf316f2 1659 );\r
1660 if (EFI_ERROR (Status)) {\r
1661 goto ReleaseIpInfo;\r
1662 }\r
1663\r
1664 //\r
1665 // Create the event for the DummyRcvToken.\r
1666 //\r
1667 Status = gBS->CreateEvent (\r
1668 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1669 TPL_NOTIFY,\r
cbf316f2 1670 IpIoDummyHandler,\r
1671 IpInfo,\r
fb115c61 1672 &Event\r
cbf316f2 1673 );\r
1674 if (EFI_ERROR (Status)) {\r
1675 goto ReleaseIpChild;\r
1676 }\r
1677\r
fb115c61 1678 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1679 IpInfo->DummyRcvToken.Ip4Token.Event = Event;\r
1680 } else {\r
1681 IpInfo->DummyRcvToken.Ip6Token.Event = Event;\r
1682 }\r
1683\r
cbf316f2 1684 //\r
1685 // Link this IpInfo into the IpIo.\r
1686 //\r
e48e37fc 1687 InsertTailList (&IpIo->IpList, &IpInfo->Entry);\r
cbf316f2 1688\r
1689 return IpInfo;\r
1690\r
1691ReleaseIpChild:\r
1692\r
1693 IpIoCloseProtocolDestroyIpChild (\r
1694 IpIo->Controller,\r
1695 IpIo->Image,\r
fb115c61 1696 IpInfo->ChildHandle,\r
1697 IpInfo->IpVersion\r
cbf316f2 1698 );\r
1699\r
1700ReleaseIpInfo:\r
1701\r
e48e37fc 1702 gBS->FreePool (IpInfo);\r
cbf316f2 1703\r
1704 return NULL;\r
1705}\r
1706\r
1707\r
1708/**\r
fb115c61 1709 Configure the IP instance of this IpInfo and start the receiving if IpConfigData\r
cbf316f2 1710 is not NULL.\r
1711\r
6aac5e5f 1712 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.\r
fb115c61 1713 @param[in, out] IpConfigData The IP configure data used to configure the IP\r
6aac5e5f 1714 instance, if NULL the IP instance is reset. If\r
1715 UseDefaultAddress is set to TRUE, and the configure\r
1716 operation succeeds, the default address information\r
fb115c61 1717 is written back in this IpConfigData.\r
cbf316f2 1718\r
6aac5e5f 1719 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully\r
1720 or no need to reconfigure it.\r
1721 @retval Others Configuration fails.\r
cbf316f2 1722\r
1723**/\r
1724EFI_STATUS\r
7b414b4e 1725EFIAPI\r
cbf316f2 1726IpIoConfigIp (\r
6aac5e5f 1727 IN OUT IP_IO_IP_INFO *IpInfo,\r
fb115c61 1728 IN OUT VOID *IpConfigData OPTIONAL\r
cbf316f2 1729 )\r
1730{\r
1731 EFI_STATUS Status;\r
fb115c61 1732 VOID *Ip;\r
b45b45b2 1733 UINT8 IpVersion;\r
cbf316f2 1734 EFI_IP4_MODE_DATA Ip4ModeData;\r
fb115c61 1735 EFI_IP6_MODE_DATA Ip6ModeData;\r
cbf316f2 1736\r
6aac5e5f 1737 ASSERT (IpInfo != NULL);\r
cbf316f2 1738\r
1739 if (IpInfo->RefCnt > 1) {\r
1740 //\r
1741 // This IP instance is shared, don't reconfigure it until it has only one\r
1742 // consumer. Currently, only the tcp children cloned from their passive parent\r
fb115c61 1743 // will share the same IP. So this cases only happens while IpConfigData is NULL,\r
cbf316f2 1744 // let the last consumer clean the IP instance.\r
1745 //\r
1746 return EFI_SUCCESS;\r
1747 }\r
1748\r
fb115c61 1749 IpVersion = IpInfo->IpVersion;\r
1750 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1751\r
cbf316f2 1752 Ip = IpInfo->Ip;\r
1753\r
fb115c61 1754 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1755 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, IpConfigData);\r
1756 } else {\r
1757 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, IpConfigData);\r
1758 }\r
1759\r
cbf316f2 1760 if (EFI_ERROR (Status)) {\r
1761 goto OnExit;\r
1762 }\r
1763\r
fb115c61 1764 if (IpConfigData != NULL) {\r
1765 if (IpInfo->IpVersion == IP_VERSION_4){\r
cbf316f2 1766\r
fb115c61 1767 if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {\r
1768 ((EFI_IP4_PROTOCOL *) Ip)->GetModeData (\r
1769 (EFI_IP4_PROTOCOL *) Ip, \r
1770 &Ip4ModeData, \r
1771 NULL, \r
1772 NULL\r
1773 );\r
cbf316f2 1774\r
fb115c61 1775 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress = Ip4ModeData.ConfigData.StationAddress;\r
1776 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask = Ip4ModeData.ConfigData.SubnetMask;\r
cbf316f2 1777 }\r
1778\r
fb115c61 1779 CopyMem (\r
1780 &IpInfo->Addr.Addr, \r
1781 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress, \r
1782 sizeof (IP4_ADDR)\r
1783 );\r
1784 CopyMem (\r
1785 &IpInfo->PreMask.SubnetMask, \r
1786 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,\r
1787 sizeof (IP4_ADDR)\r
1788 );\r
1789\r
1790 Status = ((EFI_IP4_PROTOCOL *) Ip)->Receive (\r
1791 (EFI_IP4_PROTOCOL *) Ip,\r
1792 &IpInfo->DummyRcvToken.Ip4Token\r
1793 );\r
cbf316f2 1794 if (EFI_ERROR (Status)) {\r
fb115c61 1795 ((EFI_IP4_PROTOCOL*)Ip)->Configure (Ip, NULL);\r
cbf316f2 1796 }\r
1797 } else {\r
1798\r
fb115c61 1799 ((EFI_IP6_PROTOCOL *) Ip)->GetModeData (\r
1800 (EFI_IP6_PROTOCOL *) Ip,\r
1801 &Ip6ModeData,\r
1802 NULL,\r
1803 NULL\r
1804 );\r
1805\r
1806 if (Ip6ModeData.IsConfigured) {\r
1807 CopyMem (\r
1808 &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,\r
1809 &Ip6ModeData.ConfigData.StationAddress,\r
1810 sizeof (EFI_IPv6_ADDRESS)\r
1811 );\r
1812\r
1813 if (Ip6ModeData.AddressList != NULL) {\r
1814 FreePool (Ip6ModeData.AddressList);\r
1815 }\r
1816\r
1817 if (Ip6ModeData.GroupTable != NULL) {\r
1818 FreePool (Ip6ModeData.GroupTable);\r
1819 }\r
1820\r
1821 if (Ip6ModeData.RouteTable != NULL) {\r
1822 FreePool (Ip6ModeData.RouteTable);\r
1823 }\r
1824\r
1825 if (Ip6ModeData.NeighborCache != NULL) {\r
1826 FreePool (Ip6ModeData.NeighborCache);\r
1827 }\r
1828\r
1829 if (Ip6ModeData.PrefixTable != NULL) {\r
1830 FreePool (Ip6ModeData.PrefixTable);\r
1831 }\r
1832\r
1833 if (Ip6ModeData.IcmpTypeList != NULL) {\r
1834 FreePool (Ip6ModeData.IcmpTypeList);\r
1835 }\r
1836\r
1837 } else {\r
1838 Status = EFI_NO_MAPPING;\r
1839 goto OnExit;\r
1840 } \r
1841\r
1842 CopyMem (\r
1843 &IpInfo->Addr, \r
1844 &Ip6ModeData.ConfigData.StationAddress, \r
1845 sizeof (EFI_IPv6_ADDRESS)\r
1846 );\r
1847\r
1848 Status = ((EFI_IP6_PROTOCOL *) Ip)->Receive (\r
1849 (EFI_IP6_PROTOCOL *) Ip,\r
1850 &IpInfo->DummyRcvToken.Ip6Token\r
1851 );\r
1852 if (EFI_ERROR (Status)) {\r
1853 ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);\r
1854 }\r
1855 } \r
1856 } else {\r
cbf316f2 1857 //\r
fb115c61 1858 // The IP instance is reset, set the stored Addr and SubnetMask to zero.\r
cbf316f2 1859 //\r
fb115c61 1860 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1861 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
cbf316f2 1862 }\r
1863\r
1864OnExit:\r
1865\r
1866 return Status;\r
1867}\r
1868\r
1869\r
1870/**\r
1871 Destroy an IP instance maintained in IpIo->IpList for\r
1872 sending purpose.\r
e6ff63a5 1873 \r
1874 This function pairs with IpIoAddIp(). The IpInfo is previously created by\r
1875 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance\r
1876 will be dstroyed if the RefCnt is zero.\r
cbf316f2 1877\r
6aac5e5f 1878 @param[in] IpIo Pointer to the IP_IO instance.\r
1879 @param[in] IpInfo Pointer to the IpInfo to be removed.\r
cbf316f2 1880\r
cbf316f2 1881**/\r
1882VOID\r
7b414b4e 1883EFIAPI\r
cbf316f2 1884IpIoRemoveIp (\r
e6ff63a5 1885 IN IP_IO *IpIo,\r
1886 IN IP_IO_IP_INFO *IpInfo\r
cbf316f2 1887 )\r
1888{\r
fb115c61 1889\r
b45b45b2 1890 UINT8 IpVersion;\r
fb115c61 1891\r
cbf316f2 1892 ASSERT (IpInfo->RefCnt > 0);\r
1893\r
1894 NET_PUT_REF (IpInfo);\r
1895\r
1896 if (IpInfo->RefCnt > 0) {\r
1897\r
1898 return;\r
1899 }\r
1900\r
fb115c61 1901 IpVersion = IpIo->IpVersion;\r
1902\r
1903 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1904\r
e48e37fc 1905 RemoveEntryList (&IpInfo->Entry);\r
cbf316f2 1906\r
fb115c61 1907 if (IpVersion == IP_VERSION_4){\r
1908 ((EFI_IP4_PROTOCOL *) (IpInfo->Ip))->Configure (\r
1909 (EFI_IP4_PROTOCOL *) (IpInfo->Ip),\r
1910 NULL\r
1911 );\r
1912 IpIoCloseProtocolDestroyIpChild (\r
1913 IpIo->Controller,\r
1914 IpIo->Image,\r
1915 IpInfo->ChildHandle,\r
1916 IP_VERSION_4\r
1917 );\r
1918\r
1919 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);\r
cbf316f2 1920\r
fb115c61 1921 } else {\r
cbf316f2 1922\r
fb115c61 1923 ((EFI_IP6_PROTOCOL *) (IpInfo->Ip))->Configure (\r
1924 (EFI_IP6_PROTOCOL *) (IpInfo->Ip),\r
1925 NULL\r
1926 );\r
cbf316f2 1927\r
fb115c61 1928 IpIoCloseProtocolDestroyIpChild (\r
1929 IpIo->Controller,\r
1930 IpIo->Image,\r
1931 IpInfo->ChildHandle,\r
1932 IP_VERSION_6\r
1933 );\r
1934\r
1935 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);\r
1936 }\r
1937\r
1938 FreePool (IpInfo);\r
cbf316f2 1939}\r
1940\r
1941\r
1942/**\r
1943 Find the first IP protocol maintained in IpIo whose local\r
fb115c61 1944 address is the same as Src.\r
e6ff63a5 1945 \r
1946 This function is called when the caller needs the IpIo to send data to the\r
1947 specified Src. The IpIo was added previously by IpIoAddIp().\r
cbf316f2 1948\r
6aac5e5f 1949 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.\r
fb115c61 1950 @param[in] IpVersion The version of the IP protocol to use, either\r
1951 IPv4 or IPv6.\r
6aac5e5f 1952 @param[in] Src The local IP address.\r
cbf316f2 1953\r
1954 @return Pointer to the IP protocol can be used for sending purpose and its local\r
fb115c61 1955 address is the same with Src.\r
cbf316f2 1956\r
1957**/\r
1958IP_IO_IP_INFO *\r
7b414b4e 1959EFIAPI\r
cbf316f2 1960IpIoFindSender (\r
fb115c61 1961 IN OUT IP_IO **IpIo,\r
b45b45b2 1962 IN UINT8 IpVersion,\r
fb115c61 1963 IN EFI_IP_ADDRESS *Src\r
cbf316f2 1964 )\r
1965{\r
e48e37fc 1966 LIST_ENTRY *IpIoEntry;\r
cbf316f2 1967 IP_IO *IpIoPtr;\r
e48e37fc 1968 LIST_ENTRY *IpInfoEntry;\r
cbf316f2 1969 IP_IO_IP_INFO *IpInfo;\r
1970\r
fb115c61 1971 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); \r
1972\r
cbf316f2 1973 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {\r
1974 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);\r
1975\r
fb115c61 1976 if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {\r
cbf316f2 1977 continue;\r
1978 }\r
1979\r
1980 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {\r
1981 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);\r
fb115c61 1982 if (IpInfo->IpVersion == IP_VERSION_4){\r
1983\r
1984 if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {\r
1985 *IpIo = IpIoPtr;\r
1986 return IpInfo;\r
1987 }\r
1988\r
1989 } else {\r
1990\r
1991 if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {\r
1992 *IpIo = IpIoPtr;\r
1993 return IpInfo; \r
1994 }\r
1995 } \r
cbf316f2 1996\r
cbf316f2 1997 }\r
1998 }\r
1999\r
2000 //\r
2001 // No match.\r
2002 //\r
2003 return NULL;\r
2004}\r
2005\r
2006\r
2007/**\r
e6ff63a5 2008 Get the ICMP error map information.\r
2009 \r
2010 The ErrorStatus will be returned. The IsHard and Notify are optional. If they\r
2011 are not NULL, this routine will fill them.\r
cbf316f2 2012\r
8f5e6151 2013 @param[in] IcmpError IcmpError Type.\r
fb115c61 2014 @param[in] IpVersion The version of the IP protocol to use,\r
2015 either IPv4 or IPv6.\r
2016 \r
8f5e6151 2017 @param[out] IsHard Whether it is a hard error.\r
2018 @param[out] Notify Whether it need to notify SockError.\r
cbf316f2 2019\r
6aac5e5f 2020 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.\r
cbf316f2 2021\r
2022**/\r
2023EFI_STATUS\r
7b414b4e 2024EFIAPI\r
cbf316f2 2025IpIoGetIcmpErrStatus (\r
b45b45b2 2026 IN UINT8 IcmpError,\r
2027 IN UINT8 IpVersion,\r
e6ff63a5 2028 OUT BOOLEAN *IsHard OPTIONAL,\r
2029 OUT BOOLEAN *Notify OPTIONAL\r
cbf316f2 2030 )\r
2031{\r
3cf888f5 2032 if (IpVersion == IP_VERSION_4 ) {\r
b45b45b2 2033 ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);\r
687a2e5f 2034\r
3cf888f5 2035 if (IsHard != NULL) {\r
2036 *IsHard = mIcmpErrMap[IcmpError].IsHard;\r
2037 }\r
687a2e5f 2038\r
3cf888f5 2039 if (Notify != NULL) {\r
2040 *Notify = mIcmpErrMap[IcmpError].Notify;\r
2041 }\r
2042\r
2043 switch (IcmpError) {\r
2044 case ICMP_ERR_UNREACH_NET:\r
2045 return EFI_NETWORK_UNREACHABLE;\r
2046\r
2047 case ICMP_ERR_TIMXCEED_INTRANS:\r
2048 case ICMP_ERR_TIMXCEED_REASS:\r
2049 case ICMP_ERR_UNREACH_HOST:\r
2050 return EFI_HOST_UNREACHABLE;\r
2051\r
2052 case ICMP_ERR_UNREACH_PROTOCOL:\r
2053 return EFI_PROTOCOL_UNREACHABLE;\r
2054\r
2055 case ICMP_ERR_UNREACH_PORT:\r
2056 return EFI_PORT_UNREACHABLE;\r
2057\r
2058 case ICMP_ERR_MSGSIZE:\r
2059 case ICMP_ERR_UNREACH_SRCFAIL:\r
2060 case ICMP_ERR_QUENCH:\r
2061 case ICMP_ERR_PARAMPROB:\r
2062 return EFI_ICMP_ERROR;\r
2063\r
2064 default:\r
2065 ASSERT (FALSE);\r
2066 return EFI_UNSUPPORTED;\r
2067 }\r
687a2e5f 2068\r
fb115c61 2069 } else if (IpVersion == IP_VERSION_6) {\r
2070\r
b45b45b2 2071 ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);\r
687a2e5f 2072\r
fb115c61 2073 if (IsHard != NULL) {\r
2074 *IsHard = mIcmp6ErrMap[IcmpError].IsHard;\r
2075 }\r
2076\r
2077 if (Notify != NULL) {\r
2078 *Notify = mIcmp6ErrMap[IcmpError].Notify;\r
2079 }\r
3cf888f5 2080\r
2081 switch (IcmpError) {\r
2082 case ICMP6_ERR_UNREACH_NET:\r
2083 return EFI_NETWORK_UNREACHABLE;\r
2084\r
2085 case ICMP6_ERR_UNREACH_HOST:\r
2086 case ICMP6_ERR_TIMXCEED_HOPLIMIT:\r
2087 case ICMP6_ERR_TIMXCEED_REASS: \r
2088 return EFI_HOST_UNREACHABLE;\r
2089\r
2090 case ICMP6_ERR_UNREACH_PROTOCOL:\r
2091 return EFI_PROTOCOL_UNREACHABLE;\r
2092 \r
2093 case ICMP6_ERR_UNREACH_PORT:\r
2094 return EFI_PORT_UNREACHABLE;\r
2095\r
2096 case ICMP6_ERR_PACKAGE_TOOBIG:\r
2097 case ICMP6_ERR_PARAMPROB_HEADER:\r
2098 case ICMP6_ERR_PARAMPROB_NEXHEADER:\r
2099 case ICMP6_ERR_PARAMPROB_IPV6OPTION:\r
2100 return EFI_ICMP_ERROR;\r
2101\r
2102 default:\r
2103 ASSERT (FALSE);\r
2104 return EFI_UNSUPPORTED;\r
2105 }\r
fb115c61 2106\r
2107 } else {\r
2108 //\r
2109 // Should never be here\r
2110 //\r
2111 ASSERT (FALSE);\r
2112 return EFI_UNSUPPORTED;\r
2113 }\r
2114}\r
cbf316f2 2115\r
cbf316f2 2116\r
fb115c61 2117/**\r
2118 Refresh the remote peer's Neighbor Cache entries.\r
2119\r
2120 This function is called when the caller needs the IpIo to refresh the existing\r
2121 IPv6 neighbor cache entries since the neighbor is considered reachable by the \r
2122 node has recently received a confirmation that packets sent recently to the \r
2123 neighbor were received by its IP layer. \r
2124\r
2125 @param[in] IpIo Pointer to an IP_IO instance\r
2126 @param[in] Neighbor The IP address of the neighbor\r
2127 @param[in] Timeout Time in 100-ns units that this entry will\r
2128 remain in the neighbor cache. A value of \r
2129 zero means that the entry is permanent. \r
2130 A value of non-zero means that the entry is \r
2131 dynamic and will be deleted after Timeout.\r
2132\r
2133 @retval EFI_SUCCESS The operation is completed successfully.\r
2134 @retval EFI_NOT_STARTED The IpIo is not configured.\r
2135 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.\r
2136 @retval EFI_NOT_FOUND The neighbor cache entry is not in the \r
2137 neighbor table. \r
2138 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
cbf316f2 2139\r
fb115c61 2140**/\r
2141EFI_STATUS\r
2142IpIoRefreshNeighbor (\r
2143 IN IP_IO *IpIo,\r
2144 IN EFI_IP_ADDRESS *Neighbor,\r
2145 IN UINT32 Timeout \r
2146 )\r
2147{\r
2148 EFI_IP6_PROTOCOL *Ip;\r
2149\r
2150 if (!IpIo->IsConfigured || IpIo->IpVersion != IP_VERSION_6) {\r
2151 return EFI_NOT_STARTED;\r
cbf316f2 2152 }\r
2153\r
fb115c61 2154 Ip = (EFI_IP6_PROTOCOL *) (IpIo->Ip);\r
2155\r
2156 return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);\r
cbf316f2 2157}\r
2158\r