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