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