]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
Add a UNION definition (IP_IO_IP_PROTOOCL) for EFI_IP4/6_PROTOCOL and change IP_IO...
[mirror_edk2.git] / MdeModulePkg / Library / DxeIpIoLib / DxeIpIoLib.c
CommitLineData
cbf316f2 1/** @file\r
6aac5e5f 2 IpIo Library.\r
cbf316f2 3\r
cd5ebaa0
HT
4Copyright (c) 2005 - 2009, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
cbf316f2 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
2a2e33b2 619 IN IP_IO_IP_PROTOCOL 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
2a2e33b2 944 IpInfo->Ip.Ip4->Receive (\r
945 IpInfo->Ip.Ip4,\r
946 &IpInfo->DummyRcvToken.Ip4Token\r
947 );\r
fb115c61 948 } else {\r
2a2e33b2 949 IpInfo->Ip.Ip6->Receive (\r
950 IpInfo->Ip.Ip6,\r
951 &IpInfo->DummyRcvToken.Ip6Token\r
952 );\r
fb115c61 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
cbf316f2 994 EFI_NET_SESSION_DATA Session;\r
995 NET_BUF *Pkt;\r
996\r
fb115c61 997 IpIo = (IP_IO *) Context;\r
cbf316f2 998\r
fb115c61 999 if (IpIo->IpVersion == IP_VERSION_4) {\r
1000 Status = IpIo->RcvToken.Ip4Token.Status;\r
1001 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;\r
1002 } else if (IpIo->IpVersion == IP_VERSION_6) {\r
1003 Status = IpIo->RcvToken.Ip6Token.Status;\r
1004 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;\r
1005 } else {\r
1006 return;\r
1007 }\r
cbf316f2 1008\r
36ee91ca 1009 if (EFI_ABORTED == Status) {\r
1010 //\r
1011 // The reception is actively aborted by the consumer, directly return.\r
1012 //\r
1013 return;\r
1014 }\r
1015\r
cbf316f2 1016 if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {\r
1017 //\r
6aac5e5f 1018 // @bug Only process the normal packets and the icmp error packets, if RxData is NULL\r
1019 // @bug with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although\r
1020 // @bug this should be a bug of the low layer (IP).\r
cbf316f2 1021 //\r
1022 goto Resume;\r
1023 }\r
1024\r
1025 if (NULL == IpIo->PktRcvdNotify) {\r
1026 goto CleanUp;\r
1027 }\r
1028\r
fb115c61 1029 if (IpIo->IpVersion == IP_VERSION_4) {\r
1030 if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&\r
f6b7393c 1031 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), 0)) {\r
cbf316f2 1032 //\r
1033 // The source address is not zero and it's not a unicast IP address, discard it.\r
1034 //\r
1035 goto CleanUp;\r
1036 }\r
1037\r
1038 //\r
fb115c61 1039 // Create a netbuffer representing IPv4 packet\r
cbf316f2 1040 //\r
1041 Pkt = NetbufFromExt (\r
fb115c61 1042 (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,\r
1043 RxData->Ip4RxData.FragmentCount,\r
cbf316f2 1044 0,\r
1045 0,\r
1046 IpIoExtFree,\r
fb115c61 1047 RxData->Ip4RxData.RecycleSignal\r
cbf316f2 1048 );\r
1049 if (NULL == Pkt) {\r
1050 goto CleanUp;\r
1051 }\r
1052\r
1053 //\r
1054 // Create a net session\r
1055 //\r
fb115c61 1056 Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);\r
1057 Session.Dest.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);\r
1058 Session.IpHdr.Ip4Hdr = RxData->Ip4RxData.Header;\r
a09ee46d 1059 Session.IpHdrLen = RxData->Ip4RxData.HeaderLength;\r
fb115c61 1060 Session.IpVersion = IP_VERSION_4;\r
1061 } else {\r
1062\r
f6b7393c 1063 if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {\r
fb115c61 1064 goto CleanUp;\r
1065 }\r
1066 \r
1067 //\r
1068 // Create a netbuffer representing IPv6 packet\r
1069 //\r
1070 Pkt = NetbufFromExt (\r
1071 (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,\r
1072 RxData->Ip6RxData.FragmentCount,\r
1073 0,\r
1074 0,\r
1075 IpIoExtFree,\r
1076 RxData->Ip6RxData.RecycleSignal\r
1077 );\r
1078 if (NULL == Pkt) {\r
1079 goto CleanUp;\r
1080 }\r
1081\r
1082 //\r
1083 // Create a net session\r
1084 //\r
1085 CopyMem (\r
1086 &Session.Source, \r
1087 &RxData->Ip6RxData.Header->SourceAddress,\r
1088 sizeof(EFI_IPv6_ADDRESS)\r
1089 );\r
1090 CopyMem (\r
1091 &Session.Dest, \r
1092 &RxData->Ip6RxData.Header->DestinationAddress, \r
1093 sizeof(EFI_IPv6_ADDRESS)\r
1094 );\r
1095 Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;\r
a09ee46d 1096 Session.IpHdrLen = RxData->Ip6RxData.HeaderLength;\r
fb115c61 1097 Session.IpVersion = IP_VERSION_6;\r
1098 } \r
cbf316f2 1099\r
1100 if (EFI_SUCCESS == Status) {\r
1101\r
b45b45b2 1102 IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);\r
cbf316f2 1103 } else {\r
1104 //\r
1105 // Status is EFI_ICMP_ERROR\r
1106 //\r
1107 Status = IpIoIcmpHandler (IpIo, Pkt, &Session);\r
1108 if (EFI_ERROR (Status)) {\r
1109 NetbufFree (Pkt);\r
1110 }\r
1111 }\r
1112\r
1113 goto Resume;\r
1114\r
1115CleanUp:\r
fb115c61 1116\r
1117 if (IpIo->IpVersion == IP_VERSION_4){\r
1118 gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);\r
1119 } else {\r
1120 gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal); \r
1121 }\r
cbf316f2 1122\r
1123Resume:\r
cbf316f2 1124\r
fb115c61 1125 if (IpIo->IpVersion == IP_VERSION_4){\r
2a2e33b2 1126 IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));\r
fb115c61 1127 } else {\r
2a2e33b2 1128 IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));\r
fb115c61 1129 }\r
1130}\r
cbf316f2 1131\r
36ee91ca 1132/**\r
6aac5e5f 1133 This function add IpIoListenHandlerDpc to the end of the DPC queue.\r
36ee91ca 1134\r
6aac5e5f 1135 @param[in] Event The event signaled.\r
1136 @param[in] Context The context passed in by the event notifier.\r
36ee91ca 1137\r
1138**/\r
36ee91ca 1139VOID\r
1140EFIAPI\r
1141IpIoListenHandler (\r
1142 IN EFI_EVENT Event,\r
1143 IN VOID *Context\r
1144 )\r
1145{\r
1146 //\r
1147 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
1148 //\r
d8d26fb2 1149 QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);\r
36ee91ca 1150}\r
1151\r
1152\r
cbf316f2 1153/**\r
1154 Create a new IP_IO instance.\r
e6ff63a5 1155 \r
fb115c61 1156 This function uses IP4/IP6 service binding protocol in Controller to create\r
1157 an IP4/IP6 child (aka IP4/IP6 instance).\r
cbf316f2 1158\r
6aac5e5f 1159 @param[in] Image The image handle of the driver or application that\r
e6ff63a5 1160 consumes IP_IO.\r
fb115c61 1161 @param[in] Controller The controller handle that has IP4 or IP6 service\r
1162 binding protocol installed.\r
1163 @param[in] IpVersion The version of the IP protocol to use, either\r
1164 IPv4 or IPv6. \r
cbf316f2 1165\r
e6ff63a5 1166 @return Pointer to a newly created IP_IO instance, or NULL if failed.\r
cbf316f2 1167\r
1168**/\r
1169IP_IO *\r
7b414b4e 1170EFIAPI\r
cbf316f2 1171IpIoCreate (\r
1172 IN EFI_HANDLE Image,\r
fb115c61 1173 IN EFI_HANDLE Controller,\r
b45b45b2 1174 IN UINT8 IpVersion\r
cbf316f2 1175 )\r
1176{\r
1177 EFI_STATUS Status;\r
1178 IP_IO *IpIo;\r
fb115c61 1179 EFI_EVENT Event;\r
1180\r
1181 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
cbf316f2 1182\r
e48e37fc 1183 IpIo = AllocateZeroPool (sizeof (IP_IO));\r
cbf316f2 1184 if (NULL == IpIo) {\r
1185 return NULL;\r
1186 }\r
1187\r
e48e37fc 1188 InitializeListHead (&(IpIo->PendingSndList));\r
1189 InitializeListHead (&(IpIo->IpList));\r
cbf316f2 1190 IpIo->Controller = Controller;\r
1191 IpIo->Image = Image;\r
fb115c61 1192 IpIo->IpVersion = IpVersion;\r
1193 Event = NULL;\r
cbf316f2 1194\r
1195 Status = gBS->CreateEvent (\r
1196 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1197 TPL_NOTIFY,\r
cbf316f2 1198 IpIoListenHandler,\r
1199 IpIo,\r
fb115c61 1200 &Event\r
cbf316f2 1201 );\r
1202 if (EFI_ERROR (Status)) {\r
1203 goto ReleaseIpIo;\r
1204 }\r
1205\r
fb115c61 1206 if (IpVersion == IP_VERSION_4) {\r
1207 IpIo->RcvToken.Ip4Token.Event = Event;\r
1208 } else {\r
1209 IpIo->RcvToken.Ip6Token.Event = Event;\r
1210 }\r
1211\r
cbf316f2 1212 //\r
1213 // Create an IP child and open IP protocol\r
1214 //\r
1215 Status = IpIoCreateIpChildOpenProtocol (\r
1216 Controller,\r
1217 Image,\r
1218 &IpIo->ChildHandle,\r
fb115c61 1219 IpVersion, \r
cbf316f2 1220 (VOID **)&(IpIo->Ip)\r
1221 );\r
1222 if (EFI_ERROR (Status)) {\r
1223 goto ReleaseIpIo;\r
1224 }\r
1225\r
1226 return IpIo;\r
1227\r
1228ReleaseIpIo:\r
1229\r
fb115c61 1230 if (Event != NULL) {\r
1231 gBS->CloseEvent (Event);\r
cbf316f2 1232 }\r
1233\r
e48e37fc 1234 gBS->FreePool (IpIo);\r
cbf316f2 1235\r
1236 return NULL;\r
1237}\r
1238\r
1239\r
1240/**\r
1241 Open an IP_IO instance for use.\r
e6ff63a5 1242 \r
1243 This function is called after IpIoCreate(). It is used for configuring the IP\r
1244 instance and register the callbacks and their context data for sending and\r
1245 receiving IP packets.\r
cbf316f2 1246\r
6aac5e5f 1247 @param[in, out] IpIo Pointer to an IP_IO instance that needs\r
1248 to open.\r
1249 @param[in] OpenData The configuration data and callbacks for\r
1250 the IP_IO instance.\r
cbf316f2 1251\r
6aac5e5f 1252 @retval EFI_SUCCESS The IP_IO instance opened with OpenData\r
1253 successfully.\r
1254 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to \r
1255 reopen it.\r
1256 @retval Others Error condition occurred.\r
cbf316f2 1257\r
1258**/\r
1259EFI_STATUS\r
7b414b4e 1260EFIAPI\r
cbf316f2 1261IpIoOpen (\r
6aac5e5f 1262 IN OUT IP_IO *IpIo,\r
1263 IN IP_IO_OPEN_DATA *OpenData\r
cbf316f2 1264 )\r
1265{\r
1266 EFI_STATUS Status;\r
b45b45b2 1267 UINT8 IpVersion;\r
cbf316f2 1268\r
1269 if (IpIo->IsConfigured) {\r
1270 return EFI_ACCESS_DENIED;\r
1271 }\r
1272\r
fb115c61 1273 IpVersion = IpIo->IpVersion;\r
1274\r
1275 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1276\r
cbf316f2 1277 //\r
1278 // configure ip\r
1279 //\r
fb115c61 1280 if (IpVersion == IP_VERSION_4){\r
2a2e33b2 1281 Status = IpIo->Ip.Ip4->Configure (\r
1282 IpIo->Ip.Ip4,\r
1283 &OpenData->IpConfigData.Ip4CfgData\r
1284 );\r
fb115c61 1285 } else {\r
1286\r
2a2e33b2 1287 Status = IpIo->Ip.Ip6->Configure (\r
1288 IpIo->Ip.Ip6, \r
1289 &OpenData->IpConfigData.Ip6CfgData\r
1290 );\r
fb115c61 1291 }\r
1292\r
cbf316f2 1293 if (EFI_ERROR (Status)) {\r
1294 return Status;\r
1295 }\r
1296\r
1297 //\r
6aac5e5f 1298 // @bug To delete the default route entry in this Ip, if it is:\r
1299 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified\r
1300 // @bug its code\r
cbf316f2 1301 //\r
fb115c61 1302 if (IpVersion == IP_VERSION_4){\r
2a2e33b2 1303 Status = IpIo->Ip.Ip4->Routes (\r
1304 IpIo->Ip.Ip4,\r
1305 TRUE,\r
1306 &mZeroIp4Addr,\r
1307 &mZeroIp4Addr,\r
1308 &mZeroIp4Addr\r
1309 );\r
fb115c61 1310\r
1311 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {\r
1312 return Status;\r
1313 }\r
cbf316f2 1314 }\r
1315\r
1316 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;\r
1317 IpIo->PktSentNotify = OpenData->PktSentNotify;\r
1318\r
1319 IpIo->RcvdContext = OpenData->RcvdContext;\r
1320 IpIo->SndContext = OpenData->SndContext;\r
1321\r
fb115c61 1322 if (IpVersion == IP_VERSION_4){\r
1323 IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;\r
cbf316f2 1324\r
fb115c61 1325 //\r
1326 // start to listen incoming packet\r
1327 //\r
2a2e33b2 1328 Status = IpIo->Ip.Ip4->Receive (\r
1329 IpIo->Ip.Ip4,\r
1330 &(IpIo->RcvToken.Ip4Token)\r
1331 );\r
fb115c61 1332 if (EFI_ERROR (Status)) {\r
2a2e33b2 1333 IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);\r
fb115c61 1334 goto ErrorExit;\r
1335 }\r
1336\r
1337 } else {\r
1338\r
1339 IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;\r
2a2e33b2 1340 Status = IpIo->Ip.Ip6->Receive (\r
1341 IpIo->Ip.Ip6,\r
1342 &(IpIo->RcvToken.Ip6Token)\r
1343 );\r
fb115c61 1344 if (EFI_ERROR (Status)) {\r
2a2e33b2 1345 IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);\r
fb115c61 1346 goto ErrorExit;\r
1347 }\r
cbf316f2 1348 }\r
1349\r
1350 IpIo->IsConfigured = TRUE;\r
e48e37fc 1351 InsertTailList (&mActiveIpIoList, &IpIo->Entry);\r
cbf316f2 1352\r
1353ErrorExit:\r
1354\r
1355 return Status;\r
1356}\r
1357\r
1358\r
1359/**\r
1360 Stop an IP_IO instance.\r
e6ff63a5 1361 \r
1362 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all\r
1363 the pending send/receive tokens will be canceled.\r
cbf316f2 1364\r
6aac5e5f 1365 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.\r
cbf316f2 1366\r
6aac5e5f 1367 @retval EFI_SUCCESS The IP_IO instance stopped successfully.\r
1368 @retval Others Error condition occurred.\r
cbf316f2 1369\r
1370**/\r
1371EFI_STATUS\r
e6ff63a5 1372EFIAPI\r
cbf316f2 1373IpIoStop (\r
6aac5e5f 1374 IN OUT IP_IO *IpIo\r
cbf316f2 1375 )\r
1376{\r
1377 EFI_STATUS Status;\r
cbf316f2 1378 IP_IO_IP_INFO *IpInfo;\r
b45b45b2 1379 UINT8 IpVersion;\r
cbf316f2 1380\r
1381 if (!IpIo->IsConfigured) {\r
1382 return EFI_SUCCESS;\r
1383 }\r
1384\r
fb115c61 1385 IpVersion = IpIo->IpVersion;\r
1386\r
1387 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1388\r
cbf316f2 1389 //\r
1390 // Remove the IpIo from the active IpIo list.\r
1391 //\r
e48e37fc 1392 RemoveEntryList (&IpIo->Entry);\r
cbf316f2 1393\r
cbf316f2 1394 //\r
1395 // Configure NULL Ip\r
1396 //\r
fb115c61 1397 if (IpVersion == IP_VERSION_4) {\r
2a2e33b2 1398 Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);\r
fb115c61 1399 } else {\r
2a2e33b2 1400 Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);\r
fb115c61 1401 }\r
cbf316f2 1402 if (EFI_ERROR (Status)) {\r
1403 return Status;\r
1404 }\r
1405\r
1406 IpIo->IsConfigured = FALSE;\r
1407\r
1408 //\r
1409 // Detroy the Ip List used by IpIo\r
1410 //\r
34edf2ae 1411\r
e48e37fc 1412 while (!IsListEmpty (&(IpIo->IpList))) {\r
cbf316f2 1413 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);\r
1414\r
1415 IpIoRemoveIp (IpIo, IpInfo);\r
1416 }\r
1417\r
1418 //\r
6aac5e5f 1419 // All pending send tokens should be flushed by reseting the IP instances.\r
cbf316f2 1420 //\r
e48e37fc 1421 ASSERT (IsListEmpty (&IpIo->PendingSndList));\r
cbf316f2 1422\r
1423 //\r
1424 // Close the receive event.\r
1425 //\r
fb115c61 1426 if (IpVersion == IP_VERSION_4){\r
1427 gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);\r
1428 } else {\r
1429 gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);\r
1430 }\r
cbf316f2 1431\r
1432 return EFI_SUCCESS;\r
1433}\r
1434\r
1435\r
1436/**\r
1437 Destroy an IP_IO instance.\r
e6ff63a5 1438 \r
1439 This function is paired with IpIoCreate(). The IP_IO will be closed first.\r
8f5e6151 1440 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().\r
cbf316f2 1441\r
6aac5e5f 1442 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be\r
e6ff63a5 1443 destroyed.\r
cbf316f2 1444\r
6aac5e5f 1445 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.\r
1446 @retval Others Error condition occurred.\r
cbf316f2 1447\r
1448**/\r
1449EFI_STATUS\r
7b414b4e 1450EFIAPI\r
cbf316f2 1451IpIoDestroy (\r
6aac5e5f 1452 IN OUT IP_IO *IpIo\r
cbf316f2 1453 )\r
1454{\r
1455 //\r
1456 // Stop the IpIo.\r
1457 //\r
1458 IpIoStop (IpIo);\r
1459\r
1460 //\r
1461 // Close the IP protocol and destroy the child.\r
1462 //\r
fb115c61 1463 IpIoCloseProtocolDestroyIpChild (\r
1464 IpIo->Controller,\r
1465 IpIo->Image,\r
1466 IpIo->ChildHandle,\r
1467 IpIo->IpVersion\r
1468 );\r
cbf316f2 1469\r
e48e37fc 1470 gBS->FreePool (IpIo);\r
cbf316f2 1471\r
1472 return EFI_SUCCESS;\r
1473}\r
1474\r
1475\r
1476/**\r
1477 Send out an IP packet.\r
e6ff63a5 1478 \r
1479 This function is called after IpIoOpen(). The data to be sent are wrapped in\r
1480 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be\r
1481 overriden by Sender. Other sending configs, like source address and gateway\r
1482 address etc., are specified in OverrideData.\r
cbf316f2 1483\r
6aac5e5f 1484 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP\r
1485 packet.\r
1486 @param[in, out] Pkt Pointer to the IP packet to be sent.\r
1487 @param[in] Sender The IP protocol instance used for sending.\r
8f5e6151 1488 @param[in] Context Optional context data.\r
1489 @param[in] NotifyData Optional notify data.\r
6aac5e5f 1490 @param[in] Dest The destination IP address to send this packet to.\r
1491 @param[in] OverrideData The data to override some configuration of the IP\r
1492 instance used for sending.\r
cbf316f2 1493\r
6aac5e5f 1494 @retval EFI_SUCCESS The operation is completed successfully.\r
1495 @retval EFI_NOT_STARTED The IpIo is not configured.\r
1496 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
cbf316f2 1497\r
1498**/\r
1499EFI_STATUS\r
7b414b4e 1500EFIAPI\r
cbf316f2 1501IpIoSend (\r
6aac5e5f 1502 IN OUT IP_IO *IpIo,\r
1503 IN OUT NET_BUF *Pkt,\r
1504 IN IP_IO_IP_INFO *Sender OPTIONAL,\r
1505 IN VOID *Context OPTIONAL,\r
1506 IN VOID *NotifyData OPTIONAL,\r
fb115c61 1507 IN EFI_IP_ADDRESS *Dest,\r
6aac5e5f 1508 IN IP_IO_OVERRIDE *OverrideData OPTIONAL\r
cbf316f2 1509 )\r
1510{\r
1511 EFI_STATUS Status;\r
2a2e33b2 1512 IP_IO_IP_PROTOCOL Ip;\r
cbf316f2 1513 IP_IO_SEND_ENTRY *SndEntry;\r
1514\r
fb115c61 1515 ASSERT ((IpIo->IpVersion != IP_VERSION_4) || (Dest != NULL));\r
1516\r
cbf316f2 1517 if (!IpIo->IsConfigured) {\r
1518 return EFI_NOT_STARTED;\r
1519 }\r
1520\r
1521 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;\r
1522\r
1523 //\r
1524 // create a new SndEntry\r
1525 //\r
1526 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);\r
1527 if (NULL == SndEntry) {\r
1528 return EFI_OUT_OF_RESOURCES;\r
1529 }\r
1530\r
1531 //\r
1532 // Send this Packet\r
1533 //\r
fb115c61 1534 if (IpIo->IpVersion == IP_VERSION_4){\r
2a2e33b2 1535 Status = Ip.Ip4->Transmit (\r
1536 Ip.Ip4,\r
1537 &SndEntry->SndToken.Ip4Token\r
1538 );\r
fb115c61 1539 } else {\r
2a2e33b2 1540 Status = Ip.Ip6->Transmit (\r
1541 Ip.Ip6,\r
1542 &SndEntry->SndToken.Ip6Token\r
1543 );\r
fb115c61 1544 }\r
1545\r
cbf316f2 1546 if (EFI_ERROR (Status)) {\r
1547 IpIoDestroySndEntry (SndEntry);\r
1548 }\r
1549\r
1550 return Status;\r
1551}\r
1552\r
1553\r
1554/**\r
1555 Cancel the IP transmit token which wraps this Packet.\r
1556\r
6aac5e5f 1557 @param[in] IpIo Pointer to the IP_IO instance.\r
1558 @param[in] Packet Pointer to the packet of NET_BUF to cancel.\r
cbf316f2 1559\r
1560**/\r
1561VOID\r
7b414b4e 1562EFIAPI\r
cbf316f2 1563IpIoCancelTxToken (\r
1564 IN IP_IO *IpIo,\r
1565 IN VOID *Packet\r
1566 )\r
1567{\r
e48e37fc 1568 LIST_ENTRY *Node;\r
cbf316f2 1569 IP_IO_SEND_ENTRY *SndEntry;\r
2a2e33b2 1570 IP_IO_IP_PROTOCOL Ip;\r
cbf316f2 1571\r
fb115c61 1572 ASSERT ((IpIo != NULL) && (Packet != NULL));\r
cbf316f2 1573\r
1574 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {\r
1575\r
1576 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);\r
1577\r
1578 if (SndEntry->Pkt == Packet) {\r
1579\r
1580 Ip = SndEntry->Ip;\r
fb115c61 1581\r
1582 if (IpIo->IpVersion == IP_VERSION_4) {\r
2a2e33b2 1583 Ip.Ip4->Cancel (\r
1584 Ip.Ip4,\r
1585 &SndEntry->SndToken.Ip4Token\r
1586 );\r
fb115c61 1587 } else {\r
2a2e33b2 1588 Ip.Ip6->Cancel (\r
1589 Ip.Ip6,\r
1590 &SndEntry->SndToken.Ip6Token\r
1591 );\r
fb115c61 1592 }\r
cbf316f2 1593\r
cbf316f2 1594 break;\r
1595 }\r
1596 }\r
1597\r
1598}\r
1599\r
1600\r
1601/**\r
1602 Add a new IP instance for sending data.\r
e6ff63a5 1603 \r
1604 The function is used to add the IP_IO to the IP_IO sending list. The caller\r
1605 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send\r
1606 data.\r
cbf316f2 1607\r
6aac5e5f 1608 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP\r
1609 instance for sending purpose.\r
cbf316f2 1610\r
e6ff63a5 1611 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.\r
cbf316f2 1612\r
1613**/\r
1614IP_IO_IP_INFO *\r
7b414b4e 1615EFIAPI\r
cbf316f2 1616IpIoAddIp (\r
6aac5e5f 1617 IN OUT IP_IO *IpIo\r
cbf316f2 1618 )\r
1619{\r
1620 EFI_STATUS Status;\r
1621 IP_IO_IP_INFO *IpInfo;\r
fb115c61 1622 EFI_EVENT Event;\r
cbf316f2 1623\r
6aac5e5f 1624 ASSERT (IpIo != NULL);\r
cbf316f2 1625\r
e48e37fc 1626 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));\r
cbf316f2 1627 if (IpInfo == NULL) {\r
fb115c61 1628 return NULL;\r
cbf316f2 1629 }\r
1630\r
1631 //\r
1632 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP\r
1633 // instance.\r
1634 //\r
e48e37fc 1635 InitializeListHead (&IpInfo->Entry);\r
cbf316f2 1636 IpInfo->ChildHandle = NULL;\r
fb115c61 1637 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1638 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
1639\r
1640 IpInfo->RefCnt = 1;\r
1641 IpInfo->IpVersion = IpIo->IpVersion;\r
cbf316f2 1642\r
1643 //\r
fb115c61 1644 // Create the IP instance and open the IP protocol.\r
cbf316f2 1645 //\r
1646 Status = IpIoCreateIpChildOpenProtocol (\r
1647 IpIo->Controller,\r
1648 IpIo->Image,\r
1649 &IpInfo->ChildHandle,\r
fb115c61 1650 IpInfo->IpVersion,\r
4eb65aff 1651 (VOID **) &IpInfo->Ip\r
cbf316f2 1652 );\r
1653 if (EFI_ERROR (Status)) {\r
1654 goto ReleaseIpInfo;\r
1655 }\r
1656\r
1657 //\r
1658 // Create the event for the DummyRcvToken.\r
1659 //\r
1660 Status = gBS->CreateEvent (\r
1661 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1662 TPL_NOTIFY,\r
cbf316f2 1663 IpIoDummyHandler,\r
1664 IpInfo,\r
fb115c61 1665 &Event\r
cbf316f2 1666 );\r
1667 if (EFI_ERROR (Status)) {\r
1668 goto ReleaseIpChild;\r
1669 }\r
1670\r
fb115c61 1671 if (IpInfo->IpVersion == IP_VERSION_4) {\r
1672 IpInfo->DummyRcvToken.Ip4Token.Event = Event;\r
1673 } else {\r
1674 IpInfo->DummyRcvToken.Ip6Token.Event = Event;\r
1675 }\r
1676\r
cbf316f2 1677 //\r
1678 // Link this IpInfo into the IpIo.\r
1679 //\r
e48e37fc 1680 InsertTailList (&IpIo->IpList, &IpInfo->Entry);\r
cbf316f2 1681\r
1682 return IpInfo;\r
1683\r
1684ReleaseIpChild:\r
1685\r
1686 IpIoCloseProtocolDestroyIpChild (\r
1687 IpIo->Controller,\r
1688 IpIo->Image,\r
fb115c61 1689 IpInfo->ChildHandle,\r
1690 IpInfo->IpVersion\r
cbf316f2 1691 );\r
1692\r
1693ReleaseIpInfo:\r
1694\r
e48e37fc 1695 gBS->FreePool (IpInfo);\r
cbf316f2 1696\r
1697 return NULL;\r
1698}\r
1699\r
1700\r
1701/**\r
fb115c61 1702 Configure the IP instance of this IpInfo and start the receiving if IpConfigData\r
cbf316f2 1703 is not NULL.\r
1704\r
6aac5e5f 1705 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.\r
fb115c61 1706 @param[in, out] IpConfigData The IP configure data used to configure the IP\r
6aac5e5f 1707 instance, if NULL the IP instance is reset. If\r
1708 UseDefaultAddress is set to TRUE, and the configure\r
1709 operation succeeds, the default address information\r
fb115c61 1710 is written back in this IpConfigData.\r
cbf316f2 1711\r
6aac5e5f 1712 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully\r
1713 or no need to reconfigure it.\r
1714 @retval Others Configuration fails.\r
cbf316f2 1715\r
1716**/\r
1717EFI_STATUS\r
7b414b4e 1718EFIAPI\r
cbf316f2 1719IpIoConfigIp (\r
6aac5e5f 1720 IN OUT IP_IO_IP_INFO *IpInfo,\r
fb115c61 1721 IN OUT VOID *IpConfigData OPTIONAL\r
cbf316f2 1722 )\r
1723{\r
1724 EFI_STATUS Status;\r
2a2e33b2 1725 IP_IO_IP_PROTOCOL Ip;\r
b45b45b2 1726 UINT8 IpVersion;\r
cbf316f2 1727 EFI_IP4_MODE_DATA Ip4ModeData;\r
fb115c61 1728 EFI_IP6_MODE_DATA Ip6ModeData;\r
cbf316f2 1729\r
6aac5e5f 1730 ASSERT (IpInfo != NULL);\r
cbf316f2 1731\r
1732 if (IpInfo->RefCnt > 1) {\r
1733 //\r
1734 // This IP instance is shared, don't reconfigure it until it has only one\r
1735 // consumer. Currently, only the tcp children cloned from their passive parent\r
fb115c61 1736 // will share the same IP. So this cases only happens while IpConfigData is NULL,\r
cbf316f2 1737 // let the last consumer clean the IP instance.\r
1738 //\r
1739 return EFI_SUCCESS;\r
1740 }\r
1741\r
fb115c61 1742 IpVersion = IpInfo->IpVersion;\r
1743 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1744\r
cbf316f2 1745 Ip = IpInfo->Ip;\r
1746\r
fb115c61 1747 if (IpInfo->IpVersion == IP_VERSION_4) {\r
2a2e33b2 1748 Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);\r
fb115c61 1749 } else {\r
2a2e33b2 1750 Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);\r
fb115c61 1751 }\r
1752\r
cbf316f2 1753 if (EFI_ERROR (Status)) {\r
1754 goto OnExit;\r
1755 }\r
1756\r
fb115c61 1757 if (IpConfigData != NULL) {\r
1758 if (IpInfo->IpVersion == IP_VERSION_4){\r
cbf316f2 1759\r
fb115c61 1760 if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {\r
2a2e33b2 1761 Ip.Ip4->GetModeData (\r
1762 Ip.Ip4, \r
1763 &Ip4ModeData, \r
1764 NULL, \r
1765 NULL\r
1766 );\r
cbf316f2 1767\r
fb115c61 1768 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress = Ip4ModeData.ConfigData.StationAddress;\r
1769 ((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask = Ip4ModeData.ConfigData.SubnetMask;\r
cbf316f2 1770 }\r
1771\r
fb115c61 1772 CopyMem (\r
1773 &IpInfo->Addr.Addr, \r
1774 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress, \r
1775 sizeof (IP4_ADDR)\r
1776 );\r
1777 CopyMem (\r
1778 &IpInfo->PreMask.SubnetMask, \r
1779 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,\r
1780 sizeof (IP4_ADDR)\r
1781 );\r
1782\r
2a2e33b2 1783 Status = Ip.Ip4->Receive (\r
1784 Ip.Ip4,\r
1785 &IpInfo->DummyRcvToken.Ip4Token\r
1786 );\r
cbf316f2 1787 if (EFI_ERROR (Status)) {\r
2a2e33b2 1788 Ip.Ip4->Configure (Ip.Ip4, NULL);\r
cbf316f2 1789 }\r
1790 } else {\r
2a2e33b2 1791 Ip.Ip6->GetModeData (\r
1792 Ip.Ip6,\r
1793 &Ip6ModeData,\r
1794 NULL,\r
1795 NULL\r
1796 );\r
fb115c61 1797\r
1798 if (Ip6ModeData.IsConfigured) {\r
1799 CopyMem (\r
1800 &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,\r
1801 &Ip6ModeData.ConfigData.StationAddress,\r
1802 sizeof (EFI_IPv6_ADDRESS)\r
1803 );\r
1804\r
1805 if (Ip6ModeData.AddressList != NULL) {\r
1806 FreePool (Ip6ModeData.AddressList);\r
1807 }\r
1808\r
1809 if (Ip6ModeData.GroupTable != NULL) {\r
1810 FreePool (Ip6ModeData.GroupTable);\r
1811 }\r
1812\r
1813 if (Ip6ModeData.RouteTable != NULL) {\r
1814 FreePool (Ip6ModeData.RouteTable);\r
1815 }\r
1816\r
1817 if (Ip6ModeData.NeighborCache != NULL) {\r
1818 FreePool (Ip6ModeData.NeighborCache);\r
1819 }\r
1820\r
1821 if (Ip6ModeData.PrefixTable != NULL) {\r
1822 FreePool (Ip6ModeData.PrefixTable);\r
1823 }\r
1824\r
1825 if (Ip6ModeData.IcmpTypeList != NULL) {\r
1826 FreePool (Ip6ModeData.IcmpTypeList);\r
1827 }\r
1828\r
1829 } else {\r
1830 Status = EFI_NO_MAPPING;\r
1831 goto OnExit;\r
1832 } \r
1833\r
1834 CopyMem (\r
1835 &IpInfo->Addr, \r
1836 &Ip6ModeData.ConfigData.StationAddress, \r
1837 sizeof (EFI_IPv6_ADDRESS)\r
1838 );\r
1839\r
2a2e33b2 1840 Status = Ip.Ip6->Receive (\r
1841 Ip.Ip6,\r
1842 &IpInfo->DummyRcvToken.Ip6Token\r
1843 );\r
fb115c61 1844 if (EFI_ERROR (Status)) {\r
2a2e33b2 1845 Ip.Ip6->Configure (Ip.Ip6, NULL);\r
fb115c61 1846 }\r
1847 } \r
1848 } else {\r
cbf316f2 1849 //\r
fb115c61 1850 // The IP instance is reset, set the stored Addr and SubnetMask to zero.\r
cbf316f2 1851 //\r
fb115c61 1852 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));\r
1853 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));\r
cbf316f2 1854 }\r
1855\r
1856OnExit:\r
1857\r
1858 return Status;\r
1859}\r
1860\r
1861\r
1862/**\r
1863 Destroy an IP instance maintained in IpIo->IpList for\r
1864 sending purpose.\r
e6ff63a5 1865 \r
1866 This function pairs with IpIoAddIp(). The IpInfo is previously created by\r
1867 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance\r
1868 will be dstroyed if the RefCnt is zero.\r
cbf316f2 1869\r
6aac5e5f 1870 @param[in] IpIo Pointer to the IP_IO instance.\r
1871 @param[in] IpInfo Pointer to the IpInfo to be removed.\r
cbf316f2 1872\r
cbf316f2 1873**/\r
1874VOID\r
7b414b4e 1875EFIAPI\r
cbf316f2 1876IpIoRemoveIp (\r
e6ff63a5 1877 IN IP_IO *IpIo,\r
1878 IN IP_IO_IP_INFO *IpInfo\r
cbf316f2 1879 )\r
1880{\r
fb115c61 1881\r
b45b45b2 1882 UINT8 IpVersion;\r
fb115c61 1883\r
cbf316f2 1884 ASSERT (IpInfo->RefCnt > 0);\r
1885\r
1886 NET_PUT_REF (IpInfo);\r
1887\r
1888 if (IpInfo->RefCnt > 0) {\r
1889\r
1890 return;\r
1891 }\r
1892\r
fb115c61 1893 IpVersion = IpIo->IpVersion;\r
1894\r
1895 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));\r
1896\r
e48e37fc 1897 RemoveEntryList (&IpInfo->Entry);\r
cbf316f2 1898\r
fb115c61 1899 if (IpVersion == IP_VERSION_4){\r
2a2e33b2 1900 IpInfo->Ip.Ip4->Configure (\r
1901 IpInfo->Ip.Ip4,\r
1902 NULL\r
1903 );\r
fb115c61 1904 IpIoCloseProtocolDestroyIpChild (\r
1905 IpIo->Controller,\r
1906 IpIo->Image,\r
1907 IpInfo->ChildHandle,\r
1908 IP_VERSION_4\r
1909 );\r
1910\r
1911 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);\r
cbf316f2 1912\r
fb115c61 1913 } else {\r
cbf316f2 1914\r
2a2e33b2 1915 IpInfo->Ip.Ip6->Configure (\r
1916 IpInfo->Ip.Ip6,\r
1917 NULL\r
1918 );\r
cbf316f2 1919\r
fb115c61 1920 IpIoCloseProtocolDestroyIpChild (\r
1921 IpIo->Controller,\r
1922 IpIo->Image,\r
1923 IpInfo->ChildHandle,\r
1924 IP_VERSION_6\r
1925 );\r
1926\r
1927 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);\r
1928 }\r
1929\r
1930 FreePool (IpInfo);\r
cbf316f2 1931}\r
1932\r
1933\r
1934/**\r
1935 Find the first IP protocol maintained in IpIo whose local\r
fb115c61 1936 address is the same as Src.\r
e6ff63a5 1937 \r
1938 This function is called when the caller needs the IpIo to send data to the\r
1939 specified Src. The IpIo was added previously by IpIoAddIp().\r
cbf316f2 1940\r
6aac5e5f 1941 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.\r
fb115c61 1942 @param[in] IpVersion The version of the IP protocol to use, either\r
1943 IPv4 or IPv6.\r
6aac5e5f 1944 @param[in] Src The local IP address.\r
cbf316f2 1945\r
1946 @return Pointer to the IP protocol can be used for sending purpose and its local\r
fb115c61 1947 address is the same with Src.\r
cbf316f2 1948\r
1949**/\r
1950IP_IO_IP_INFO *\r
7b414b4e 1951EFIAPI\r
cbf316f2 1952IpIoFindSender (\r
fb115c61 1953 IN OUT IP_IO **IpIo,\r
b45b45b2 1954 IN UINT8 IpVersion,\r
fb115c61 1955 IN EFI_IP_ADDRESS *Src\r
cbf316f2 1956 )\r
1957{\r
e48e37fc 1958 LIST_ENTRY *IpIoEntry;\r
cbf316f2 1959 IP_IO *IpIoPtr;\r
e48e37fc 1960 LIST_ENTRY *IpInfoEntry;\r
cbf316f2 1961 IP_IO_IP_INFO *IpInfo;\r
1962\r
fb115c61 1963 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); \r
1964\r
cbf316f2 1965 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {\r
1966 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);\r
1967\r
fb115c61 1968 if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {\r
cbf316f2 1969 continue;\r
1970 }\r
1971\r
1972 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {\r
1973 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);\r
fb115c61 1974 if (IpInfo->IpVersion == IP_VERSION_4){\r
1975\r
1976 if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {\r
1977 *IpIo = IpIoPtr;\r
1978 return IpInfo;\r
1979 }\r
1980\r
1981 } else {\r
1982\r
1983 if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {\r
1984 *IpIo = IpIoPtr;\r
1985 return IpInfo; \r
1986 }\r
1987 } \r
cbf316f2 1988\r
cbf316f2 1989 }\r
1990 }\r
1991\r
1992 //\r
1993 // No match.\r
1994 //\r
1995 return NULL;\r
1996}\r
1997\r
1998\r
1999/**\r
e6ff63a5 2000 Get the ICMP error map information.\r
2001 \r
2002 The ErrorStatus will be returned. The IsHard and Notify are optional. If they\r
2003 are not NULL, this routine will fill them.\r
cbf316f2 2004\r
8f5e6151 2005 @param[in] IcmpError IcmpError Type.\r
fb115c61 2006 @param[in] IpVersion The version of the IP protocol to use,\r
3b1464d5 2007 either IPv4 or IPv6. \r
2008 @param[out] IsHard If TRUE, indicates that it is a hard error.\r
2009 @param[out] Notify If TRUE, SockError needs to be notified.\r
cbf316f2 2010\r
6aac5e5f 2011 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.\r
cbf316f2 2012\r
2013**/\r
2014EFI_STATUS\r
7b414b4e 2015EFIAPI\r
cbf316f2 2016IpIoGetIcmpErrStatus (\r
b45b45b2 2017 IN UINT8 IcmpError,\r
2018 IN UINT8 IpVersion,\r
e6ff63a5 2019 OUT BOOLEAN *IsHard OPTIONAL,\r
2020 OUT BOOLEAN *Notify OPTIONAL\r
cbf316f2 2021 )\r
2022{\r
3cf888f5 2023 if (IpVersion == IP_VERSION_4 ) {\r
b45b45b2 2024 ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);\r
687a2e5f 2025\r
3cf888f5 2026 if (IsHard != NULL) {\r
2027 *IsHard = mIcmpErrMap[IcmpError].IsHard;\r
2028 }\r
687a2e5f 2029\r
3cf888f5 2030 if (Notify != NULL) {\r
2031 *Notify = mIcmpErrMap[IcmpError].Notify;\r
2032 }\r
2033\r
2034 switch (IcmpError) {\r
2035 case ICMP_ERR_UNREACH_NET:\r
2036 return EFI_NETWORK_UNREACHABLE;\r
2037\r
2038 case ICMP_ERR_TIMXCEED_INTRANS:\r
2039 case ICMP_ERR_TIMXCEED_REASS:\r
2040 case ICMP_ERR_UNREACH_HOST:\r
2041 return EFI_HOST_UNREACHABLE;\r
2042\r
2043 case ICMP_ERR_UNREACH_PROTOCOL:\r
2044 return EFI_PROTOCOL_UNREACHABLE;\r
2045\r
2046 case ICMP_ERR_UNREACH_PORT:\r
2047 return EFI_PORT_UNREACHABLE;\r
2048\r
2049 case ICMP_ERR_MSGSIZE:\r
2050 case ICMP_ERR_UNREACH_SRCFAIL:\r
2051 case ICMP_ERR_QUENCH:\r
2052 case ICMP_ERR_PARAMPROB:\r
2053 return EFI_ICMP_ERROR;\r
2054\r
2055 default:\r
2056 ASSERT (FALSE);\r
2057 return EFI_UNSUPPORTED;\r
2058 }\r
687a2e5f 2059\r
fb115c61 2060 } else if (IpVersion == IP_VERSION_6) {\r
2061\r
b45b45b2 2062 ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);\r
687a2e5f 2063\r
fb115c61 2064 if (IsHard != NULL) {\r
2065 *IsHard = mIcmp6ErrMap[IcmpError].IsHard;\r
2066 }\r
2067\r
2068 if (Notify != NULL) {\r
2069 *Notify = mIcmp6ErrMap[IcmpError].Notify;\r
2070 }\r
3cf888f5 2071\r
2072 switch (IcmpError) {\r
2073 case ICMP6_ERR_UNREACH_NET:\r
2074 return EFI_NETWORK_UNREACHABLE;\r
2075\r
2076 case ICMP6_ERR_UNREACH_HOST:\r
2077 case ICMP6_ERR_TIMXCEED_HOPLIMIT:\r
2078 case ICMP6_ERR_TIMXCEED_REASS: \r
2079 return EFI_HOST_UNREACHABLE;\r
2080\r
2081 case ICMP6_ERR_UNREACH_PROTOCOL:\r
2082 return EFI_PROTOCOL_UNREACHABLE;\r
2083 \r
2084 case ICMP6_ERR_UNREACH_PORT:\r
2085 return EFI_PORT_UNREACHABLE;\r
2086\r
2087 case ICMP6_ERR_PACKAGE_TOOBIG:\r
2088 case ICMP6_ERR_PARAMPROB_HEADER:\r
2089 case ICMP6_ERR_PARAMPROB_NEXHEADER:\r
2090 case ICMP6_ERR_PARAMPROB_IPV6OPTION:\r
2091 return EFI_ICMP_ERROR;\r
2092\r
2093 default:\r
2094 ASSERT (FALSE);\r
2095 return EFI_UNSUPPORTED;\r
2096 }\r
fb115c61 2097\r
2098 } else {\r
2099 //\r
2100 // Should never be here\r
2101 //\r
2102 ASSERT (FALSE);\r
2103 return EFI_UNSUPPORTED;\r
2104 }\r
2105}\r
cbf316f2 2106\r
cbf316f2 2107\r
fb115c61 2108/**\r
2109 Refresh the remote peer's Neighbor Cache entries.\r
2110\r
2111 This function is called when the caller needs the IpIo to refresh the existing\r
2112 IPv6 neighbor cache entries since the neighbor is considered reachable by the \r
2113 node has recently received a confirmation that packets sent recently to the \r
2114 neighbor were received by its IP layer. \r
2115\r
2116 @param[in] IpIo Pointer to an IP_IO instance\r
2117 @param[in] Neighbor The IP address of the neighbor\r
2118 @param[in] Timeout Time in 100-ns units that this entry will\r
2119 remain in the neighbor cache. A value of \r
2120 zero means that the entry is permanent. \r
2121 A value of non-zero means that the entry is \r
2122 dynamic and will be deleted after Timeout.\r
2123\r
2124 @retval EFI_SUCCESS The operation is completed successfully.\r
2125 @retval EFI_NOT_STARTED The IpIo is not configured.\r
2126 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.\r
2127 @retval EFI_NOT_FOUND The neighbor cache entry is not in the \r
2128 neighbor table. \r
2129 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
cbf316f2 2130\r
fb115c61 2131**/\r
2132EFI_STATUS\r
2133IpIoRefreshNeighbor (\r
2134 IN IP_IO *IpIo,\r
2135 IN EFI_IP_ADDRESS *Neighbor,\r
2136 IN UINT32 Timeout \r
2137 )\r
2138{\r
2139 EFI_IP6_PROTOCOL *Ip;\r
2140\r
2141 if (!IpIo->IsConfigured || IpIo->IpVersion != IP_VERSION_6) {\r
2142 return EFI_NOT_STARTED;\r
cbf316f2 2143 }\r
2144\r
2a2e33b2 2145 Ip = IpIo->Ip.Ip6;\r
fb115c61 2146\r
2147 return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);\r
cbf316f2 2148}\r
2149\r