]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
Fixed GCC 4.4 build issues due to EFIAPI not being used when required.
[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
e798cd87 590EFIAPI\r
cbf316f2 591IpIoExtFree (\r
592 IN VOID *Event\r
593 )\r
594{\r
595 gBS->SignalEvent ((EFI_EVENT) Event);\r
596}\r
597\r
598\r
599/**\r
600 Create a send entry to wrap a packet before sending\r
601 out it through IP.\r
602\r
6aac5e5f 603 @param[in, out] IpIo Pointer to the IP_IO instance.\r
604 @param[in, out] Pkt Pointer to the packet.\r
605 @param[in] Sender Pointer to the IP sender.\r
606 @param[in] Context Pointer to the context.\r
607 @param[in] NotifyData Pointer to the notify data.\r
608 @param[in] Dest Pointer to the destination IP address.\r
609 @param[in] Override Pointer to the overriden IP_IO data.\r
cbf316f2 610\r
611 @return Pointer to the data structure created to wrap the packet. If NULL,\r
6aac5e5f 612 @return resource limit occurred.\r
cbf316f2 613\r
614**/\r
cbf316f2 615IP_IO_SEND_ENTRY *\r
616IpIoCreateSndEntry (\r
6aac5e5f 617 IN OUT IP_IO *IpIo,\r
618 IN OUT NET_BUF *Pkt,\r
fb115c61 619 IN VOID *Sender,\r
6aac5e5f 620 IN VOID *Context OPTIONAL,\r
621 IN VOID *NotifyData OPTIONAL,\r
fb115c61 622 IN EFI_IP_ADDRESS *Dest OPTIONAL,\r
6aac5e5f 623 IN IP_IO_OVERRIDE *Override\r
cbf316f2 624 )\r
625{\r
626 IP_IO_SEND_ENTRY *SndEntry;\r
fb115c61 627 EFI_EVENT Event; \r
cbf316f2 628 EFI_STATUS Status;\r
fb115c61 629 NET_FRAGMENT *ExtFragment;\r
630 UINT32 FragmentCount;\r
631 IP_IO_OVERRIDE *OverrideData;\r
632 IP_IO_IP_TX_DATA *TxData;\r
633 EFI_IP4_TRANSMIT_DATA *Ip4TxData;\r
634 EFI_IP6_TRANSMIT_DATA *Ip6TxData;\r
635\r
636 if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {\r
637 return NULL;\r
638 }\r
639\r
640 Event = NULL;\r
641 TxData = NULL;\r
642 OverrideData = NULL;\r
cbf316f2 643\r
644 //\r
645 // Allocate resource for SndEntry\r
646 //\r
e48e37fc 647 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));\r
cbf316f2 648 if (NULL == SndEntry) {\r
649 return NULL;\r
650 }\r
651\r
cbf316f2 652 Status = gBS->CreateEvent (\r
653 EVT_NOTIFY_SIGNAL,\r
e48e37fc 654 TPL_NOTIFY,\r
cbf316f2 655 IpIoTransmitHandler,\r
656 SndEntry,\r
fb115c61 657 &Event\r
cbf316f2 658 );\r
659 if (EFI_ERROR (Status)) {\r
fb115c61 660 goto ON_ERROR;\r
cbf316f2 661 }\r
662\r
fb115c61 663 FragmentCount = Pkt->BlockOpNum;\r
664\r
cbf316f2 665 //\r
666 // Allocate resource for TxData\r
667 //\r
fb115c61 668 TxData = (IP_IO_IP_TX_DATA *) AllocatePool (\r
669 sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)\r
cbf316f2 670 );\r
671\r
672 if (NULL == TxData) {\r
fb115c61 673 goto ON_ERROR;\r
674 }\r
675\r
676 //\r
677 // Build a fragment table to contain the fragments in the packet. \r
678 //\r
679 if (IpIo->IpVersion == IP_VERSION_4) {\r
680 ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;\r
681 } else {\r
682 ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;\r
cbf316f2 683 }\r
684\r
fb115c61 685 NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);\r
686\r
687\r
cbf316f2 688 //\r
689 // Allocate resource for OverrideData if needed\r
690 //\r
cbf316f2 691 if (NULL != Override) {\r
692\r
fb115c61 693 OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);\r
cbf316f2 694 if (NULL == OverrideData) {\r
fb115c61 695 goto ON_ERROR;\r
cbf316f2 696 }\r
cbf316f2 697 }\r
698\r
699 //\r
fb115c61 700 // Set other fields of TxData except the fragment table\r
cbf316f2 701 //\r
fb115c61 702 if (IpIo->IpVersion == IP_VERSION_4) {\r
cbf316f2 703\r
fb115c61 704 Ip4TxData = &TxData->Ip4TxData;\r
cbf316f2 705\r
fb115c61 706 CopyMem (&Ip4TxData->DestinationAddress, Dest, sizeof (EFI_IPv4_ADDRESS));\r
cbf316f2 707\r
fb115c61 708 Ip4TxData->OverrideData = &OverrideData->Ip4OverrideData;\r
709 Ip4TxData->OptionsLength = 0;\r
710 Ip4TxData->OptionsBuffer = NULL;\r
711 Ip4TxData->TotalDataLength = Pkt->TotalSize;\r
712 Ip4TxData->FragmentCount = FragmentCount;\r
713\r
714 //\r
715 // Set the fields of SndToken\r
716 //\r
717 SndEntry->SndToken.Ip4Token.Event = Event;\r
718 SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;\r
719 } else {\r
720\r
721 Ip6TxData = &TxData->Ip6TxData;\r
722\r
723 if (Dest != NULL) {\r
724 CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));\r
725 } else {\r
726 ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));\r
727 }\r
728\r
729 Ip6TxData->OverrideData = &OverrideData->Ip6OverrideData;\r
730 Ip6TxData->DataLength = Pkt->TotalSize;\r
731 Ip6TxData->FragmentCount = FragmentCount;\r
732 Ip6TxData->ExtHdrsLength = 0;\r
733 Ip6TxData->ExtHdrs = NULL;\r
734 \r
735 //\r
736 // Set the fields of SndToken\r
737 //\r
738 SndEntry->SndToken.Ip6Token.Event = Event;\r
739 SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;\r
740 }\r
cbf316f2 741\r
742 //\r
743 // Set the fields of SndEntry\r
744 //\r
745 SndEntry->IpIo = IpIo;\r
6aac5e5f 746 SndEntry->Ip = Sender;\r
cbf316f2 747 SndEntry->Context = Context;\r
748 SndEntry->NotifyData = NotifyData;\r
749\r
750 SndEntry->Pkt = Pkt;\r
751 NET_GET_REF (Pkt);\r
752\r
e48e37fc 753 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);\r
cbf316f2 754\r
755 return SndEntry;\r
756\r
fb115c61 757ON_ERROR:\r
758\r
759 if (OverrideData != NULL) {\r
760 FreePool (OverrideData);\r
761 }\r
cbf316f2 762\r
fb115c61 763 if (TxData != NULL) {\r
764 FreePool (TxData);\r
765 }\r
cbf316f2 766\r
fb115c61 767 if (SndEntry != NULL) {\r
768 FreePool (SndEntry);\r
769 }\r
cbf316f2 770\r
fb115c61 771 if (Event != NULL) {\r
772 gBS->CloseEvent (Event);\r
773 }\r
cbf316f2 774\r
775 return NULL;\r
776}\r
777\r
778\r
779/**\r
780 Destroy the SndEntry.\r
e6ff63a5 781 \r
782 This function pairs with IpIoCreateSndEntry().\r
cbf316f2 783\r
6aac5e5f 784 @param[in] SndEntry Pointer to the send entry to be destroyed.\r
cbf316f2 785\r
cbf316f2 786**/\r
cbf316f2 787VOID\r
788IpIoDestroySndEntry (\r
789 IN IP_IO_SEND_ENTRY *SndEntry\r
790 )\r
791{\r
fb115c61 792 EFI_EVENT Event;\r
793 IP_IO_IP_TX_DATA *TxData;\r
794 IP_IO_OVERRIDE *Override;\r
795\r
796 if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {\r
797 Event = SndEntry->SndToken.Ip4Token.Event;\r
798 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;\r
799 Override = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;\r
800 } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {\r
801 Event = SndEntry->SndToken.Ip6Token.Event;\r
802 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;\r
803 Override = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;\r
804 } else {\r
805 return ;\r
806 }\r
cbf316f2 807\r
fb115c61 808 gBS->CloseEvent (Event);\r
cbf316f2 809\r
fb115c61 810 FreePool (TxData);\r
811\r
812 if (NULL != Override) {\r
813 FreePool (Override);\r
cbf316f2 814 }\r
815\r
cbf316f2 816 NetbufFree (SndEntry->Pkt);\r
cbf316f2 817\r
e48e37fc 818 RemoveEntryList (&SndEntry->Entry);\r
cbf316f2 819\r
fb115c61 820 FreePool (SndEntry);\r
cbf316f2 821}\r
822\r
823\r
824/**\r
825 Notify function for IP transmit token.\r
826\r
6aac5e5f 827 @param[in] Context The context passed in by the event notifier.\r
cbf316f2 828\r
cbf316f2 829**/\r
cbf316f2 830VOID\r
831EFIAPI\r
36ee91ca 832IpIoTransmitHandlerDpc (\r
cbf316f2 833 IN VOID *Context\r
834 )\r
835{\r
836 IP_IO *IpIo;\r
837 IP_IO_SEND_ENTRY *SndEntry;\r
fb115c61 838 EFI_STATUS Status;\r
cbf316f2 839\r
840 SndEntry = (IP_IO_SEND_ENTRY *) Context;\r
841\r
842 IpIo = SndEntry->IpIo;\r
843\r
fb115c61 844 if (IpIo->IpVersion == IP_VERSION_4) {\r
845 Status = SndEntry->SndToken.Ip4Token.Status;\r
846 } else if (IpIo->IpVersion == IP_VERSION_6){\r
847 Status = SndEntry->SndToken.Ip6Token.Status;\r
848 } else {\r
849 return ;\r
850 }\r
851\r
8de75da2 852 if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {\r
cbf316f2 853 IpIo->PktSentNotify (\r
fb115c61 854 Status,\r
cbf316f2 855 SndEntry->Context,\r
856 SndEntry->Ip,\r
857 SndEntry->NotifyData\r
858 );\r
859 }\r
860\r
861 IpIoDestroySndEntry (SndEntry);\r
862}\r
863\r
6aac5e5f 864\r
36ee91ca 865/**\r
866 Notify function for IP transmit token.\r
867\r
6aac5e5f 868 @param[in] Event The event signaled.\r
869 @param[in] Context The context passed in by the event notifier.\r
36ee91ca 870\r
36ee91ca 871**/\r
36ee91ca 872VOID\r
873EFIAPI\r
874IpIoTransmitHandler (\r
875 IN EFI_EVENT Event,\r
876 IN VOID *Context\r
877 )\r
878{\r
879 //\r
880 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK\r
881 //\r
d8d26fb2 882 QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);\r
36ee91ca 883}\r
884\r
cbf316f2 885\r
886/**\r
887 The dummy handler for the dummy IP receive token.\r
888\r
6aac5e5f 889 @param[in] Context The context passed in by the event notifier.\r
cbf316f2 890\r
cbf316f2 891**/\r
cbf316f2 892VOID\r
893EFIAPI\r
36ee91ca 894IpIoDummyHandlerDpc (\r
cbf316f2 895 IN VOID *Context\r
896 )\r
897{\r
898 IP_IO_IP_INFO *IpInfo;\r
fb115c61 899 EFI_STATUS Status;\r
900 EFI_EVENT RecycleEvent;\r
cbf316f2 901\r
cbf316f2 902 IpInfo = (IP_IO_IP_INFO *) Context;\r
cbf316f2 903\r
fb115c61 904 if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {\r
905 return ;\r
906 }\r
907\r
908 RecycleEvent = NULL;\r
909\r
910 if (IpInfo->IpVersion == IP_VERSION_4) {\r
911 Status = IpInfo->DummyRcvToken.Ip4Token.Status;\r
912\r
913 if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {\r
914 RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;\r
915 }\r
916 } else {\r
917 Status = IpInfo->DummyRcvToken.Ip6Token.Status;\r
918\r
919 if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {\r
920 RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;\r
921 }\r
922 }\r
923\r
924\r
925\r
926 if (EFI_ABORTED == Status) {\r
36ee91ca 927 //\r
928 // The reception is actively aborted by the consumer, directly return.\r
929 //\r
930 return;\r
fb115c61 931 } else if (EFI_SUCCESS == Status) {\r
932 //\r
933 // Recycle the RxData.\r
934 //\r
935 ASSERT (RecycleEvent != NULL);\r
cbf316f2 936\r
fb115c61 937 gBS->SignalEvent (RecycleEvent);\r
cbf316f2 938 }\r
939\r
fb115c61 940 //\r
941 // Continue the receive.\r
942 //\r
943 if (IpInfo->IpVersion == IP_VERSION_4) {\r
944 ((EFI_IP4_PROTOCOL *) (IpInfo->Ip))->Receive (\r
945 (EFI_IP4_PROTOCOL *) (IpInfo->Ip),\r
946 &IpInfo->DummyRcvToken.Ip4Token\r
947 );\r
948 } else {\r
949 ((EFI_IP6_PROTOCOL *) (IpInfo->Ip))->Receive (\r
950 (EFI_IP6_PROTOCOL *) (IpInfo->Ip),\r
951 &IpInfo->DummyRcvToken.Ip6Token\r
952 );\r
953 }\r
cbf316f2 954}\r
955\r
956\r
957/**\r
6aac5e5f 958 This function add IpIoDummyHandlerDpc to the end of the DPC queue.\r
cbf316f2 959\r
6aac5e5f 960 @param[in] Event The event signaled.\r
961 @param[in] Context The context passed in by the event notifier.\r
cbf316f2 962\r
cbf316f2 963**/\r
cbf316f2 964VOID\r
965EFIAPI\r
36ee91ca 966IpIoDummyHandler (\r
cbf316f2 967 IN EFI_EVENT Event,\r
968 IN VOID *Context\r
969 )\r
36ee91ca 970{\r
971 //\r
972 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK\r
973 //\r
d8d26fb2 974 QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);\r
36ee91ca 975}\r
976\r
977\r
978/**\r
979 Notify function for the IP receive token, used to process\r
980 the received IP packets.\r
981\r
6aac5e5f 982 @param[in] Context The context passed in by the event notifier.\r
36ee91ca 983\r
36ee91ca 984**/\r
36ee91ca 985VOID\r
986EFIAPI\r
987IpIoListenHandlerDpc (\r
988 IN VOID *Context\r
989 )\r
cbf316f2 990{\r
991 IP_IO *IpIo;\r
992 EFI_STATUS Status;\r
fb115c61 993 IP_IO_IP_RX_DATA *RxData;\r
994 VOID *Ip;\r
cbf316f2 995 EFI_NET_SESSION_DATA Session;\r
996 NET_BUF *Pkt;\r
997\r
fb115c61 998 IpIo = (IP_IO *) Context;\r
999 Ip = IpIo->Ip;\r
cbf316f2 1000\r
fb115c61 1001 if (IpIo->IpVersion == IP_VERSION_4) {\r
1002 Status = IpIo->RcvToken.Ip4Token.Status;\r
1003 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;\r
1004 } else if (IpIo->IpVersion == IP_VERSION_6) {\r
1005 Status = IpIo->RcvToken.Ip6Token.Status;\r
1006 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;\r
1007 } else {\r
1008 return;\r
1009 }\r
cbf316f2 1010\r
36ee91ca 1011 if (EFI_ABORTED == Status) {\r
1012 //\r
1013 // The reception is actively aborted by the consumer, directly return.\r
1014 //\r
1015 return;\r
1016 }\r
1017\r
cbf316f2 1018 if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {\r
1019 //\r
6aac5e5f 1020 // @bug Only process the normal packets and the icmp error packets, if RxData is NULL\r
1021 // @bug with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although\r
1022 // @bug this should be a bug of the low layer (IP).\r
cbf316f2 1023 //\r
1024 goto Resume;\r
1025 }\r
1026\r
1027 if (NULL == IpIo->PktRcvdNotify) {\r
1028 goto CleanUp;\r
1029 }\r
1030\r
fb115c61 1031 if (IpIo->IpVersion == IP_VERSION_4) {\r
1032 if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&\r
f6b7393c 1033 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), 0)) {\r
cbf316f2 1034 //\r
1035 // The source address is not zero and it's not a unicast IP address, discard it.\r
1036 //\r
1037 goto CleanUp;\r
1038 }\r
1039\r
1040 //\r
fb115c61 1041 // Create a netbuffer representing IPv4 packet\r
cbf316f2 1042 //\r
1043 Pkt = NetbufFromExt (\r
fb115c61 1044 (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,\r
1045 RxData->Ip4RxData.FragmentCount,\r
cbf316f2 1046 0,\r
1047 0,\r
1048 IpIoExtFree,\r
fb115c61 1049 RxData->Ip4RxData.RecycleSignal\r
cbf316f2 1050 );\r
1051 if (NULL == Pkt) {\r
1052 goto CleanUp;\r
1053 }\r
1054\r
1055 //\r
1056 // Create a net session\r
1057 //\r
fb115c61 1058 Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);\r
1059 Session.Dest.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);\r
1060 Session.IpHdr.Ip4Hdr = RxData->Ip4RxData.Header;\r
a09ee46d 1061 Session.IpHdrLen = RxData->Ip4RxData.HeaderLength;\r
fb115c61 1062 Session.IpVersion = IP_VERSION_4;\r
1063 } else {\r
1064\r
f6b7393c 1065 if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {\r
fb115c61 1066 goto CleanUp;\r
1067 }\r
1068 \r
1069 //\r
1070 // Create a netbuffer representing IPv6 packet\r
1071 //\r
1072 Pkt = NetbufFromExt (\r
1073 (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,\r
1074 RxData->Ip6RxData.FragmentCount,\r
1075 0,\r
1076 0,\r
1077 IpIoExtFree,\r
1078 RxData->Ip6RxData.RecycleSignal\r
1079 );\r
1080 if (NULL == Pkt) {\r
1081 goto CleanUp;\r
1082 }\r
1083\r
1084 //\r
1085 // Create a net session\r
1086 //\r
1087 CopyMem (\r
1088 &Session.Source, \r
1089 &RxData->Ip6RxData.Header->SourceAddress,\r
1090 sizeof(EFI_IPv6_ADDRESS)\r
1091 );\r
1092 CopyMem (\r
1093 &Session.Dest, \r
1094 &RxData->Ip6RxData.Header->DestinationAddress, \r
1095 sizeof(EFI_IPv6_ADDRESS)\r
1096 );\r
1097 Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;\r
a09ee46d 1098 Session.IpHdrLen = RxData->Ip6RxData.HeaderLength;\r
fb115c61 1099 Session.IpVersion = IP_VERSION_6;\r
1100 } \r
cbf316f2 1101\r
1102 if (EFI_SUCCESS == Status) {\r
1103\r
b45b45b2 1104 IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);\r
cbf316f2 1105 } else {\r
1106 //\r
1107 // Status is EFI_ICMP_ERROR\r
1108 //\r
1109 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);\r
1110 if (EFI_ERROR (Status)) {\r
1111 NetbufFree (Pkt);\r
1112 }\r
1113 }\r
1114\r
1115 goto Resume;\r
1116\r
1117CleanUp:\r
fb115c61 1118\r
1119 if (IpIo->IpVersion == IP_VERSION_4){\r
1120 gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);\r
1121 } else {\r
1122 gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal); \r
1123 }\r
cbf316f2 1124\r
1125Resume:\r
cbf316f2 1126\r
fb115c61 1127 if (IpIo->IpVersion == IP_VERSION_4){\r
1128 ((EFI_IP4_PROTOCOL *) Ip)->Receive (Ip, &(IpIo->RcvToken.Ip4Token));\r
1129 } else {\r
1130 ((EFI_IP6_PROTOCOL *) Ip)->Receive (Ip, &(IpIo->RcvToken.Ip6Token));\r
1131 }\r
1132}\r
cbf316f2 1133\r
36ee91ca 1134/**\r
6aac5e5f 1135 This function add IpIoListenHandlerDpc to the end of the DPC queue.\r
36ee91ca 1136\r
6aac5e5f 1137 @param[in] Event The event signaled.\r
1138 @param[in] Context The context passed in by the event notifier.\r
36ee91ca 1139\r
1140**/\r
36ee91ca 1141VOID\r
1142EFIAPI\r
1143IpIoListenHandler (\r
1144 IN EFI_EVENT Event,\r
1145 IN VOID *Context\r
1146 )\r
1147{\r
1148 //\r
1149 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
1150 //\r
d8d26fb2 1151 QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);\r
36ee91ca 1152}\r
1153\r
1154\r
cbf316f2 1155/**\r
1156 Create a new IP_IO instance.\r
e6ff63a5 1157 \r
fb115c61 1158 This function uses IP4/IP6 service binding protocol in Controller to create\r
1159 an IP4/IP6 child (aka IP4/IP6 instance).\r
cbf316f2 1160\r
6aac5e5f 1161 @param[in] Image The image handle of the driver or application that\r
e6ff63a5 1162 consumes IP_IO.\r
fb115c61 1163 @param[in] Controller The controller handle that has IP4 or IP6 service\r
1164 binding protocol installed.\r
1165 @param[in] IpVersion The version of the IP protocol to use, either\r
1166 IPv4 or IPv6. \r
cbf316f2 1167\r
e6ff63a5 1168 @return Pointer to a newly created IP_IO instance, or NULL if failed.\r
cbf316f2 1169\r
1170**/\r
1171IP_IO *\r
7b414b4e 1172EFIAPI\r
cbf316f2 1173IpIoCreate (\r
1174 IN EFI_HANDLE Image,\r
fb115c61 1175 IN EFI_HANDLE Controller,\r
b45b45b2 1176 IN UINT8 IpVersion\r
cbf316f2 1177 )\r
1178{\r
1179 EFI_STATUS Status;\r
1180 IP_IO *IpIo;\r
fb115c61 1181 EFI_EVENT Event;\r
1182\r
1183 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
cbf316f2 1184\r
e48e37fc 1185 IpIo = AllocateZeroPool (sizeof (IP_IO));\r
cbf316f2 1186 if (NULL == IpIo) {\r
1187 return NULL;\r
1188 }\r
1189\r
e48e37fc 1190 InitializeListHead (&(IpIo->PendingSndList));\r
1191 InitializeListHead (&(IpIo->IpList));\r
cbf316f2 1192 IpIo->Controller = Controller;\r
1193 IpIo->Image = Image;\r
fb115c61 1194 IpIo->IpVersion = IpVersion;\r
1195 Event = NULL;\r
cbf316f2 1196\r
1197 Status = gBS->CreateEvent (\r
1198 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1199 TPL_NOTIFY,\r
cbf316f2 1200 IpIoListenHandler,\r
1201 IpIo,\r
fb115c61 1202 &Event\r
cbf316f2 1203 );\r
1204 if (EFI_ERROR (Status)) {\r
1205 goto ReleaseIpIo;\r
1206 }\r
1207\r
fb115c61 1208 if (IpVersion == IP_VERSION_4) {\r
1209 IpIo->RcvToken.Ip4Token.Event = Event;\r
1210 } else {\r
1211 IpIo->RcvToken.Ip6Token.Event = Event;\r
1212 }\r
1213\r
cbf316f2 1214 //\r
1215 // Create an IP child and open IP protocol\r
1216 //\r
1217 Status = IpIoCreateIpChildOpenProtocol (\r
1218 Controller,\r
1219 Image,\r
1220 &IpIo->ChildHandle,\r
fb115c61 1221 IpVersion, \r
cbf316f2 1222 (VOID **)&(IpIo->Ip)\r
1223 );\r
1224 if (EFI_ERROR (Status)) {\r
1225 goto ReleaseIpIo;\r
1226 }\r
1227\r
1228 return IpIo;\r
1229\r
1230ReleaseIpIo:\r
1231\r
fb115c61 1232 if (Event != NULL) {\r
1233 gBS->CloseEvent (Event);\r
cbf316f2 1234 }\r
1235\r
e48e37fc 1236 gBS->FreePool (IpIo);\r
cbf316f2 1237\r
1238 return NULL;\r
1239}\r
1240\r
1241\r
1242/**\r
1243 Open an IP_IO instance for use.\r
e6ff63a5 1244 \r
1245 This function is called after IpIoCreate(). It is used for configuring the IP\r
1246 instance and register the callbacks and their context data for sending and\r
1247 receiving IP packets.\r
cbf316f2 1248\r
6aac5e5f 1249 @param[in, out] IpIo Pointer to an IP_IO instance that needs\r
1250 to open.\r
1251 @param[in] OpenData The configuration data and callbacks for\r
1252 the IP_IO instance.\r
cbf316f2 1253\r
6aac5e5f 1254 @retval EFI_SUCCESS The IP_IO instance opened with OpenData\r
1255 successfully.\r
1256 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to \r
1257 reopen it.\r
1258 @retval Others Error condition occurred.\r
cbf316f2 1259\r
1260**/\r
1261EFI_STATUS\r
7b414b4e 1262EFIAPI\r
cbf316f2 1263IpIoOpen (\r
6aac5e5f 1264 IN OUT IP_IO *IpIo,\r
1265 IN IP_IO_OPEN_DATA *OpenData\r
cbf316f2 1266 )\r
1267{\r
1268 EFI_STATUS Status;\r
fb115c61 1269 VOID *Ip;\r
b45b45b2 1270 UINT8 IpVersion;\r
cbf316f2 1271\r
1272 if (IpIo->IsConfigured) {\r
1273 return EFI_ACCESS_DENIED;\r
1274 }\r
1275\r
fb115c61 1276 IpVersion = IpIo->IpVersion;\r
1277\r
1278 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1279\r
cbf316f2 1280 Ip = IpIo->Ip;\r
1281\r
1282 //\r
1283 // configure ip\r
1284 //\r
fb115c61 1285 if (IpVersion == IP_VERSION_4){\r
1286 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure (\r
1287 (EFI_IP4_PROTOCOL *) Ip,\r
1288 &OpenData->IpConfigData.Ip4CfgData\r
1289 );\r
1290 } else {\r
1291\r
1292 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure (\r
1293 (EFI_IP6_PROTOCOL *) Ip, \r
1294 &OpenData->IpConfigData.Ip6CfgData\r
1295 );\r
1296 }\r
1297\r
cbf316f2 1298 if (EFI_ERROR (Status)) {\r
1299 return Status;\r
1300 }\r
1301\r
1302 //\r
6aac5e5f 1303 // @bug To delete the default route entry in this Ip, if it is:\r
1304 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified\r
1305 // @bug its code\r
cbf316f2 1306 //\r
fb115c61 1307 if (IpVersion == IP_VERSION_4){\r
1308 Status = ((EFI_IP4_PROTOCOL *) Ip)->Routes (\r
1309 (EFI_IP4_PROTOCOL *) Ip,\r
1310 TRUE,\r
1311 &mZeroIp4Addr,\r
1312 &mZeroIp4Addr,\r
1313 &mZeroIp4Addr\r
1314 );\r
1315\r
1316 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {\r
1317 return Status;\r
1318 }\r
cbf316f2 1319 }\r
1320\r
1321 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;\r
1322 IpIo->PktSentNotify = OpenData->PktSentNotify;\r
1323\r
1324 IpIo->RcvdContext = OpenData->RcvdContext;\r
1325 IpIo->SndContext = OpenData->SndContext;\r
1326\r
fb115c61 1327 if (IpVersion == IP_VERSION_4){\r
1328 IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;\r
cbf316f2 1329\r
fb115c61 1330 //\r
1331 // start to listen incoming packet\r
1332 //\r
1333 Status = ((EFI_IP4_PROTOCOL *) Ip)->Receive (\r
1334 (EFI_IP4_PROTOCOL *) Ip,\r
1335 &(IpIo->RcvToken.Ip4Token)\r
1336 );\r
1337 if (EFI_ERROR (Status)) {\r
1338 ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, NULL);\r
1339 goto ErrorExit;\r
1340 }\r
1341\r
1342 } else {\r
1343\r
1344 IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;\r
1345 Status = ((EFI_IP6_PROTOCOL *) Ip)->Receive (\r
1346 (EFI_IP6_PROTOCOL *) Ip,\r
1347 &(IpIo->RcvToken.Ip6Token)\r
1348 );\r
1349 if (EFI_ERROR (Status)) {\r
1350 ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);\r
1351 goto ErrorExit;\r
1352 }\r
cbf316f2 1353 }\r
1354\r
1355 IpIo->IsConfigured = TRUE;\r
e48e37fc 1356 InsertTailList (&mActiveIpIoList, &IpIo->Entry);\r
cbf316f2 1357\r
1358ErrorExit:\r
1359\r
1360 return Status;\r
1361}\r
1362\r
1363\r
1364/**\r
1365 Stop an IP_IO instance.\r
e6ff63a5 1366 \r
1367 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all\r
1368 the pending send/receive tokens will be canceled.\r
cbf316f2 1369\r
6aac5e5f 1370 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.\r
cbf316f2 1371\r
6aac5e5f 1372 @retval EFI_SUCCESS The IP_IO instance stopped successfully.\r
1373 @retval Others Error condition occurred.\r
cbf316f2 1374\r
1375**/\r
1376EFI_STATUS\r
e6ff63a5 1377EFIAPI\r
cbf316f2 1378IpIoStop (\r
6aac5e5f 1379 IN OUT IP_IO *IpIo\r
cbf316f2 1380 )\r
1381{\r
1382 EFI_STATUS Status;\r
fb115c61 1383 VOID *Ip;\r
cbf316f2 1384 IP_IO_IP_INFO *IpInfo;\r
b45b45b2 1385 UINT8 IpVersion;\r
cbf316f2 1386\r
1387 if (!IpIo->IsConfigured) {\r
1388 return EFI_SUCCESS;\r
1389 }\r
1390\r
fb115c61 1391 IpVersion = IpIo->IpVersion;\r
1392\r
1393 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1394\r
cbf316f2 1395 //\r
1396 // Remove the IpIo from the active IpIo list.\r
1397 //\r
e48e37fc 1398 RemoveEntryList (&IpIo->Entry);\r
cbf316f2 1399\r
1400 Ip = IpIo->Ip;\r
1401\r
1402 //\r
1403 // Configure NULL Ip\r
1404 //\r
fb115c61 1405 if (IpVersion == IP_VERSION_4) {\r
1406 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, NULL);\r
1407 } else {\r
1408 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);\r
1409 }\r
cbf316f2 1410 if (EFI_ERROR (Status)) {\r
1411 return Status;\r
1412 }\r
1413\r
1414 IpIo->IsConfigured = FALSE;\r
1415\r
1416 //\r
1417 // Detroy the Ip List used by IpIo\r
1418 //\r
34edf2ae 1419\r
e48e37fc 1420 while (!IsListEmpty (&(IpIo->IpList))) {\r
cbf316f2 1421 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);\r
1422\r
1423 IpIoRemoveIp (IpIo, IpInfo);\r
1424 }\r
1425\r
1426 //\r
6aac5e5f 1427 // All pending send tokens should be flushed by reseting the IP instances.\r
cbf316f2 1428 //\r
e48e37fc 1429 ASSERT (IsListEmpty (&IpIo->PendingSndList));\r
cbf316f2 1430\r
1431 //\r
1432 // Close the receive event.\r
1433 //\r
fb115c61 1434 if (IpVersion == IP_VERSION_4){\r
1435 gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);\r
1436 } else {\r
1437 gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);\r
1438 }\r
cbf316f2 1439\r
1440 return EFI_SUCCESS;\r
1441}\r
1442\r
1443\r
1444/**\r
1445 Destroy an IP_IO instance.\r
e6ff63a5 1446 \r
1447 This function is paired with IpIoCreate(). The IP_IO will be closed first.\r
8f5e6151 1448 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().\r
cbf316f2 1449\r
6aac5e5f 1450 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be\r
e6ff63a5 1451 destroyed.\r
cbf316f2 1452\r
6aac5e5f 1453 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.\r
1454 @retval Others Error condition occurred.\r
cbf316f2 1455\r
1456**/\r
1457EFI_STATUS\r
7b414b4e 1458EFIAPI\r
cbf316f2 1459IpIoDestroy (\r
6aac5e5f 1460 IN OUT IP_IO *IpIo\r
cbf316f2 1461 )\r
1462{\r
1463 //\r
1464 // Stop the IpIo.\r
1465 //\r
1466 IpIoStop (IpIo);\r
1467\r
1468 //\r
1469 // Close the IP protocol and destroy the child.\r
1470 //\r
fb115c61 1471 IpIoCloseProtocolDestroyIpChild (\r
1472 IpIo->Controller,\r
1473 IpIo->Image,\r
1474 IpIo->ChildHandle,\r
1475 IpIo->IpVersion\r
1476 );\r
cbf316f2 1477\r
e48e37fc 1478 gBS->FreePool (IpIo);\r
cbf316f2 1479\r
1480 return EFI_SUCCESS;\r
1481}\r
1482\r
1483\r
1484/**\r
1485 Send out an IP packet.\r
e6ff63a5 1486 \r
1487 This function is called after IpIoOpen(). The data to be sent are wrapped in\r
1488 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be\r
1489 overriden by Sender. Other sending configs, like source address and gateway\r
1490 address etc., are specified in OverrideData.\r
cbf316f2 1491\r
6aac5e5f 1492 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP\r
1493 packet.\r
1494 @param[in, out] Pkt Pointer to the IP packet to be sent.\r
1495 @param[in] Sender The IP protocol instance used for sending.\r
8f5e6151 1496 @param[in] Context Optional context data.\r
1497 @param[in] NotifyData Optional notify data.\r
6aac5e5f 1498 @param[in] Dest The destination IP address to send this packet to.\r
1499 @param[in] OverrideData The data to override some configuration of the IP\r
1500 instance used for sending.\r
cbf316f2 1501\r
6aac5e5f 1502 @retval EFI_SUCCESS The operation is completed successfully.\r
1503 @retval EFI_NOT_STARTED The IpIo is not configured.\r
1504 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
cbf316f2 1505\r
1506**/\r
1507EFI_STATUS\r
7b414b4e 1508EFIAPI\r
cbf316f2 1509IpIoSend (\r
6aac5e5f 1510 IN OUT IP_IO *IpIo,\r
1511 IN OUT NET_BUF *Pkt,\r
1512 IN IP_IO_IP_INFO *Sender OPTIONAL,\r
1513 IN VOID *Context OPTIONAL,\r
1514 IN VOID *NotifyData OPTIONAL,\r
fb115c61 1515 IN EFI_IP_ADDRESS *Dest,\r
6aac5e5f 1516 IN IP_IO_OVERRIDE *OverrideData OPTIONAL\r
cbf316f2 1517 )\r
1518{\r
1519 EFI_STATUS Status;\r
fb115c61 1520 VOID *Ip;\r
cbf316f2 1521 IP_IO_SEND_ENTRY *SndEntry;\r
1522\r
fb115c61 1523 ASSERT ((IpIo->IpVersion != IP_VERSION_4) || (Dest != NULL));\r
1524\r
cbf316f2 1525 if (!IpIo->IsConfigured) {\r
1526 return EFI_NOT_STARTED;\r
1527 }\r
1528\r
1529 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;\r
1530\r
1531 //\r
1532 // create a new SndEntry\r
1533 //\r
1534 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);\r
1535 if (NULL == SndEntry) {\r
1536 return EFI_OUT_OF_RESOURCES;\r
1537 }\r
1538\r
1539 //\r
1540 // Send this Packet\r
1541 //\r
fb115c61 1542 if (IpIo->IpVersion == IP_VERSION_4){\r
1543 Status = ((EFI_IP4_PROTOCOL *) Ip)->Transmit (\r
1544 (EFI_IP4_PROTOCOL *) Ip,\r
1545 &SndEntry->SndToken.Ip4Token\r
1546 );\r
1547 } else {\r
1548 Status = ((EFI_IP6_PROTOCOL *) Ip)->Transmit (\r
1549 (EFI_IP6_PROTOCOL *) Ip,\r
1550 &SndEntry->SndToken.Ip6Token\r
1551 );\r
1552 }\r
1553\r
cbf316f2 1554 if (EFI_ERROR (Status)) {\r
1555 IpIoDestroySndEntry (SndEntry);\r
1556 }\r
1557\r
1558 return Status;\r
1559}\r
1560\r
1561\r
1562/**\r
1563 Cancel the IP transmit token which wraps this Packet.\r
1564\r
6aac5e5f 1565 @param[in] IpIo Pointer to the IP_IO instance.\r
1566 @param[in] Packet Pointer to the packet of NET_BUF to cancel.\r
cbf316f2 1567\r
1568**/\r
1569VOID\r
7b414b4e 1570EFIAPI\r
cbf316f2 1571IpIoCancelTxToken (\r
1572 IN IP_IO *IpIo,\r
1573 IN VOID *Packet\r
1574 )\r
1575{\r
e48e37fc 1576 LIST_ENTRY *Node;\r
cbf316f2 1577 IP_IO_SEND_ENTRY *SndEntry;\r
fb115c61 1578 VOID *Ip;\r
cbf316f2 1579\r
fb115c61 1580 ASSERT ((IpIo != NULL) && (Packet != NULL));\r
cbf316f2 1581\r
1582 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {\r
1583\r
1584 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);\r
1585\r
1586 if (SndEntry->Pkt == Packet) {\r
1587\r
1588 Ip = SndEntry->Ip;\r
fb115c61 1589\r
1590 if (IpIo->IpVersion == IP_VERSION_4) {\r
1591 ((EFI_IP4_PROTOCOL *) Ip)->Cancel (\r
1592 (EFI_IP4_PROTOCOL *) Ip,\r
1593 &SndEntry->SndToken.Ip4Token\r
1594 );\r
1595 } else {\r
1596 ((EFI_IP6_PROTOCOL *) Ip)->Cancel (\r
1597 (EFI_IP6_PROTOCOL *) Ip,\r
1598 &SndEntry->SndToken.Ip6Token\r
1599 );\r
1600 }\r
cbf316f2 1601\r
cbf316f2 1602 break;\r
1603 }\r
1604 }\r
1605\r
1606}\r
1607\r
1608\r
1609/**\r
1610 Add a new IP instance for sending data.\r
e6ff63a5 1611 \r
1612 The function is used to add the IP_IO to the IP_IO sending list. The caller\r
1613 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send\r
1614 data.\r
cbf316f2 1615\r
6aac5e5f 1616 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP\r
1617 instance for sending purpose.\r
cbf316f2 1618\r
e6ff63a5 1619 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.\r
cbf316f2 1620\r
1621**/\r
1622IP_IO_IP_INFO *\r
7b414b4e 1623EFIAPI\r
cbf316f2 1624IpIoAddIp (\r
6aac5e5f 1625 IN OUT IP_IO *IpIo\r
cbf316f2 1626 )\r
1627{\r
1628 EFI_STATUS Status;\r
1629 IP_IO_IP_INFO *IpInfo;\r
fb115c61 1630 EFI_EVENT Event;\r
cbf316f2 1631\r
6aac5e5f 1632 ASSERT (IpIo != NULL);\r
cbf316f2 1633\r
e48e37fc 1634 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));\r
cbf316f2 1635 if (IpInfo == NULL) {\r
fb115c61 1636 return NULL;\r
cbf316f2 1637 }\r
1638\r
1639 //\r
1640 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP\r
1641 // instance.\r
1642 //\r
e48e37fc 1643 InitializeListHead (&IpInfo->Entry);\r
cbf316f2 1644 IpInfo->ChildHandle = NULL;\r
fb115c61 1645 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1646 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
1647\r
1648 IpInfo->RefCnt = 1;\r
1649 IpInfo->IpVersion = IpIo->IpVersion;\r
cbf316f2 1650\r
1651 //\r
fb115c61 1652 // Create the IP instance and open the IP protocol.\r
cbf316f2 1653 //\r
1654 Status = IpIoCreateIpChildOpenProtocol (\r
1655 IpIo->Controller,\r
1656 IpIo->Image,\r
1657 &IpInfo->ChildHandle,\r
fb115c61 1658 IpInfo->IpVersion,\r
4eb65aff 1659 (VOID **) &IpInfo->Ip\r
cbf316f2 1660 );\r
1661 if (EFI_ERROR (Status)) {\r
1662 goto ReleaseIpInfo;\r
1663 }\r
1664\r
1665 //\r
1666 // Create the event for the DummyRcvToken.\r
1667 //\r
1668 Status = gBS->CreateEvent (\r
1669 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1670 TPL_NOTIFY,\r
cbf316f2 1671 IpIoDummyHandler,\r
1672 IpInfo,\r
fb115c61 1673 &Event\r
cbf316f2 1674 );\r
1675 if (EFI_ERROR (Status)) {\r
1676 goto ReleaseIpChild;\r
1677 }\r
1678\r
fb115c61 1679 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1680 IpInfo->DummyRcvToken.Ip4Token.Event = Event;\r
1681 } else {\r
1682 IpInfo->DummyRcvToken.Ip6Token.Event = Event;\r
1683 }\r
1684\r
cbf316f2 1685 //\r
1686 // Link this IpInfo into the IpIo.\r
1687 //\r
e48e37fc 1688 InsertTailList (&IpIo->IpList, &IpInfo->Entry);\r
cbf316f2 1689\r
1690 return IpInfo;\r
1691\r
1692ReleaseIpChild:\r
1693\r
1694 IpIoCloseProtocolDestroyIpChild (\r
1695 IpIo->Controller,\r
1696 IpIo->Image,\r
fb115c61 1697 IpInfo->ChildHandle,\r
1698 IpInfo->IpVersion\r
cbf316f2 1699 );\r
1700\r
1701ReleaseIpInfo:\r
1702\r
e48e37fc 1703 gBS->FreePool (IpInfo);\r
cbf316f2 1704\r
1705 return NULL;\r
1706}\r
1707\r
1708\r
1709/**\r
fb115c61 1710 Configure the IP instance of this IpInfo and start the receiving if IpConfigData\r
cbf316f2 1711 is not NULL.\r
1712\r
6aac5e5f 1713 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.\r
fb115c61 1714 @param[in, out] IpConfigData The IP configure data used to configure the IP\r
6aac5e5f 1715 instance, if NULL the IP instance is reset. If\r
1716 UseDefaultAddress is set to TRUE, and the configure\r
1717 operation succeeds, the default address information\r
fb115c61 1718 is written back in this IpConfigData.\r
cbf316f2 1719\r
6aac5e5f 1720 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully\r
1721 or no need to reconfigure it.\r
1722 @retval Others Configuration fails.\r
cbf316f2 1723\r
1724**/\r
1725EFI_STATUS\r
7b414b4e 1726EFIAPI\r
cbf316f2 1727IpIoConfigIp (\r
6aac5e5f 1728 IN OUT IP_IO_IP_INFO *IpInfo,\r
fb115c61 1729 IN OUT VOID *IpConfigData OPTIONAL\r
cbf316f2 1730 )\r
1731{\r
1732 EFI_STATUS Status;\r
fb115c61 1733 VOID *Ip;\r
b45b45b2 1734 UINT8 IpVersion;\r
cbf316f2 1735 EFI_IP4_MODE_DATA Ip4ModeData;\r
fb115c61 1736 EFI_IP6_MODE_DATA Ip6ModeData;\r
cbf316f2 1737\r
6aac5e5f 1738 ASSERT (IpInfo != NULL);\r
cbf316f2 1739\r
1740 if (IpInfo->RefCnt > 1) {\r
1741 //\r
1742 // This IP instance is shared, don't reconfigure it until it has only one\r
1743 // consumer. Currently, only the tcp children cloned from their passive parent\r
fb115c61 1744 // will share the same IP. So this cases only happens while IpConfigData is NULL,\r
cbf316f2 1745 // let the last consumer clean the IP instance.\r
1746 //\r
1747 return EFI_SUCCESS;\r
1748 }\r
1749\r
fb115c61 1750 IpVersion = IpInfo->IpVersion;\r
1751 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1752\r
cbf316f2 1753 Ip = IpInfo->Ip;\r
1754\r
fb115c61 1755 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1756 Status = ((EFI_IP4_PROTOCOL *) Ip)->Configure ((EFI_IP4_PROTOCOL *) Ip, IpConfigData);\r
1757 } else {\r
1758 Status = ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, IpConfigData);\r
1759 }\r
1760\r
cbf316f2 1761 if (EFI_ERROR (Status)) {\r
1762 goto OnExit;\r
1763 }\r
1764\r
fb115c61 1765 if (IpConfigData != NULL) {\r
1766 if (IpInfo->IpVersion == IP_VERSION_4){\r
cbf316f2 1767\r
fb115c61 1768 if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {\r
1769 ((EFI_IP4_PROTOCOL *) Ip)->GetModeData (\r
1770 (EFI_IP4_PROTOCOL *) Ip, \r
1771 &Ip4ModeData, \r
1772 NULL, \r
1773 NULL\r
1774 );\r
cbf316f2 1775\r
fb115c61 1776 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress = Ip4ModeData.ConfigData.StationAddress;\r
1777 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask = Ip4ModeData.ConfigData.SubnetMask;\r
cbf316f2 1778 }\r
1779\r
fb115c61 1780 CopyMem (\r
1781 &IpInfo->Addr.Addr, \r
1782 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress, \r
1783 sizeof (IP4_ADDR)\r
1784 );\r
1785 CopyMem (\r
1786 &IpInfo->PreMask.SubnetMask, \r
1787 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,\r
1788 sizeof (IP4_ADDR)\r
1789 );\r
1790\r
1791 Status = ((EFI_IP4_PROTOCOL *) Ip)->Receive (\r
1792 (EFI_IP4_PROTOCOL *) Ip,\r
1793 &IpInfo->DummyRcvToken.Ip4Token\r
1794 );\r
cbf316f2 1795 if (EFI_ERROR (Status)) {\r
fb115c61 1796 ((EFI_IP4_PROTOCOL*)Ip)->Configure (Ip, NULL);\r
cbf316f2 1797 }\r
1798 } else {\r
1799\r
fb115c61 1800 ((EFI_IP6_PROTOCOL *) Ip)->GetModeData (\r
1801 (EFI_IP6_PROTOCOL *) Ip,\r
1802 &Ip6ModeData,\r
1803 NULL,\r
1804 NULL\r
1805 );\r
1806\r
1807 if (Ip6ModeData.IsConfigured) {\r
1808 CopyMem (\r
1809 &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,\r
1810 &Ip6ModeData.ConfigData.StationAddress,\r
1811 sizeof (EFI_IPv6_ADDRESS)\r
1812 );\r
1813\r
1814 if (Ip6ModeData.AddressList != NULL) {\r
1815 FreePool (Ip6ModeData.AddressList);\r
1816 }\r
1817\r
1818 if (Ip6ModeData.GroupTable != NULL) {\r
1819 FreePool (Ip6ModeData.GroupTable);\r
1820 }\r
1821\r
1822 if (Ip6ModeData.RouteTable != NULL) {\r
1823 FreePool (Ip6ModeData.RouteTable);\r
1824 }\r
1825\r
1826 if (Ip6ModeData.NeighborCache != NULL) {\r
1827 FreePool (Ip6ModeData.NeighborCache);\r
1828 }\r
1829\r
1830 if (Ip6ModeData.PrefixTable != NULL) {\r
1831 FreePool (Ip6ModeData.PrefixTable);\r
1832 }\r
1833\r
1834 if (Ip6ModeData.IcmpTypeList != NULL) {\r
1835 FreePool (Ip6ModeData.IcmpTypeList);\r
1836 }\r
1837\r
1838 } else {\r
1839 Status = EFI_NO_MAPPING;\r
1840 goto OnExit;\r
1841 } \r
1842\r
1843 CopyMem (\r
1844 &IpInfo->Addr, \r
1845 &Ip6ModeData.ConfigData.StationAddress, \r
1846 sizeof (EFI_IPv6_ADDRESS)\r
1847 );\r
1848\r
1849 Status = ((EFI_IP6_PROTOCOL *) Ip)->Receive (\r
1850 (EFI_IP6_PROTOCOL *) Ip,\r
1851 &IpInfo->DummyRcvToken.Ip6Token\r
1852 );\r
1853 if (EFI_ERROR (Status)) {\r
1854 ((EFI_IP6_PROTOCOL *) Ip)->Configure ((EFI_IP6_PROTOCOL *) Ip, NULL);\r
1855 }\r
1856 } \r
1857 } else {\r
cbf316f2 1858 //\r
fb115c61 1859 // The IP instance is reset, set the stored Addr and SubnetMask to zero.\r
cbf316f2 1860 //\r
fb115c61 1861 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1862 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
cbf316f2 1863 }\r
1864\r
1865OnExit:\r
1866\r
1867 return Status;\r
1868}\r
1869\r
1870\r
1871/**\r
1872 Destroy an IP instance maintained in IpIo->IpList for\r
1873 sending purpose.\r
e6ff63a5 1874 \r
1875 This function pairs with IpIoAddIp(). The IpInfo is previously created by\r
1876 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance\r
1877 will be dstroyed if the RefCnt is zero.\r
cbf316f2 1878\r
6aac5e5f 1879 @param[in] IpIo Pointer to the IP_IO instance.\r
1880 @param[in] IpInfo Pointer to the IpInfo to be removed.\r
cbf316f2 1881\r
cbf316f2 1882**/\r
1883VOID\r
7b414b4e 1884EFIAPI\r
cbf316f2 1885IpIoRemoveIp (\r
e6ff63a5 1886 IN IP_IO *IpIo,\r
1887 IN IP_IO_IP_INFO *IpInfo\r
cbf316f2 1888 )\r
1889{\r
fb115c61 1890\r
b45b45b2 1891 UINT8 IpVersion;\r
fb115c61 1892\r
cbf316f2 1893 ASSERT (IpInfo->RefCnt > 0);\r
1894\r
1895 NET_PUT_REF (IpInfo);\r
1896\r
1897 if (IpInfo->RefCnt > 0) {\r
1898\r
1899 return;\r
1900 }\r
1901\r
fb115c61 1902 IpVersion = IpIo->IpVersion;\r
1903\r
1904 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1905\r
e48e37fc 1906 RemoveEntryList (&IpInfo->Entry);\r
cbf316f2 1907\r
fb115c61 1908 if (IpVersion == IP_VERSION_4){\r
1909 ((EFI_IP4_PROTOCOL *) (IpInfo->Ip))->Configure (\r
1910 (EFI_IP4_PROTOCOL *) (IpInfo->Ip),\r
1911 NULL\r
1912 );\r
1913 IpIoCloseProtocolDestroyIpChild (\r
1914 IpIo->Controller,\r
1915 IpIo->Image,\r
1916 IpInfo->ChildHandle,\r
1917 IP_VERSION_4\r
1918 );\r
1919\r
1920 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);\r
cbf316f2 1921\r
fb115c61 1922 } else {\r
cbf316f2 1923\r
fb115c61 1924 ((EFI_IP6_PROTOCOL *) (IpInfo->Ip))->Configure (\r
1925 (EFI_IP6_PROTOCOL *) (IpInfo->Ip),\r
1926 NULL\r
1927 );\r
cbf316f2 1928\r
fb115c61 1929 IpIoCloseProtocolDestroyIpChild (\r
1930 IpIo->Controller,\r
1931 IpIo->Image,\r
1932 IpInfo->ChildHandle,\r
1933 IP_VERSION_6\r
1934 );\r
1935\r
1936 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);\r
1937 }\r
1938\r
1939 FreePool (IpInfo);\r
cbf316f2 1940}\r
1941\r
1942\r
1943/**\r
1944 Find the first IP protocol maintained in IpIo whose local\r
fb115c61 1945 address is the same as Src.\r
e6ff63a5 1946 \r
1947 This function is called when the caller needs the IpIo to send data to the\r
1948 specified Src. The IpIo was added previously by IpIoAddIp().\r
cbf316f2 1949\r
6aac5e5f 1950 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.\r
fb115c61 1951 @param[in] IpVersion The version of the IP protocol to use, either\r
1952 IPv4 or IPv6.\r
6aac5e5f 1953 @param[in] Src The local IP address.\r
cbf316f2 1954\r
1955 @return Pointer to the IP protocol can be used for sending purpose and its local\r
fb115c61 1956 address is the same with Src.\r
cbf316f2 1957\r
1958**/\r
1959IP_IO_IP_INFO *\r
7b414b4e 1960EFIAPI\r
cbf316f2 1961IpIoFindSender (\r
fb115c61 1962 IN OUT IP_IO **IpIo,\r
b45b45b2 1963 IN UINT8 IpVersion,\r
fb115c61 1964 IN EFI_IP_ADDRESS *Src\r
cbf316f2 1965 )\r
1966{\r
e48e37fc 1967 LIST_ENTRY *IpIoEntry;\r
cbf316f2 1968 IP_IO *IpIoPtr;\r
e48e37fc 1969 LIST_ENTRY *IpInfoEntry;\r
cbf316f2 1970 IP_IO_IP_INFO *IpInfo;\r
1971\r
fb115c61 1972 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); \r
1973\r
cbf316f2 1974 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {\r
1975 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);\r
1976\r
fb115c61 1977 if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {\r
cbf316f2 1978 continue;\r
1979 }\r
1980\r
1981 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {\r
1982 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);\r
fb115c61 1983 if (IpInfo->IpVersion == IP_VERSION_4){\r
1984\r
1985 if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {\r
1986 *IpIo = IpIoPtr;\r
1987 return IpInfo;\r
1988 }\r
1989\r
1990 } else {\r
1991\r
1992 if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {\r
1993 *IpIo = IpIoPtr;\r
1994 return IpInfo; \r
1995 }\r
1996 } \r
cbf316f2 1997\r
cbf316f2 1998 }\r
1999 }\r
2000\r
2001 //\r
2002 // No match.\r
2003 //\r
2004 return NULL;\r
2005}\r
2006\r
2007\r
2008/**\r
e6ff63a5 2009 Get the ICMP error map information.\r
2010 \r
2011 The ErrorStatus will be returned. The IsHard and Notify are optional. If they\r
2012 are not NULL, this routine will fill them.\r
cbf316f2 2013\r
8f5e6151 2014 @param[in] IcmpError IcmpError Type.\r
fb115c61 2015 @param[in] IpVersion The version of the IP protocol to use,\r
3b1464d5 2016 either IPv4 or IPv6. \r
2017 @param[out] IsHard If TRUE, indicates that it is a hard error.\r
2018 @param[out] Notify If TRUE, SockError needs to be notified.\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