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