]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Application/Ping6/Ping6.c
Update ipsecconfig and ping6 due to ShellLib update.
[mirror_edk2.git] / NetworkPkg / Application / Ping6 / Ping6.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 The implementation for Ping6 application.\r
3\r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php.\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Library/ShellLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/BaseLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/DebugLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/HiiLib.h>\r
23#include <Library/NetLib.h>\r
24\r
25#include <Protocol/Cpu.h>\r
26#include <Protocol/ServiceBinding.h>\r
27#include <Protocol/Ip6.h>\r
28#include <Protocol/Ip6Config.h>\r
29\r
30#include "Ping6.h"\r
31\r
32SHELL_PARAM_ITEM Ping6ParamList[] = {\r
33 {\r
34 L"-l",\r
35 TypeValue\r
36 },\r
37 {\r
38 L"-n",\r
39 TypeValue\r
40 },\r
41 {\r
42 L"-s",\r
43 TypeValue\r
44 },\r
45 {\r
46 L"-?",\r
47 TypeFlag\r
48 },\r
49 {\r
50 NULL,\r
51 TypeMax\r
52 },\r
53};\r
54\r
55//\r
56// Global Variables in Ping6 application.\r
57//\r
58EFI_HII_HANDLE mHiiHandle;\r
59CONST CHAR16 *mIp6DstString;\r
60CONST CHAR16 *mIp6SrcString;\r
61EFI_GUID mEfiPing6Guid = EFI_PING6_GUID;\r
62UINT32 mFrequency = 0;\r
63/**\r
64 Get and caculate the frequency in tick/ms.\r
65 The result is saved in the globle variable mFrequency\r
66\r
67 @retval EFI_SUCCESS Caculated the frequency successfully.\r
68 @retval Others Failed to caculate the frequency.\r
69\r
70**/\r
71EFI_STATUS\r
72Ping6GetFrequency (\r
73 VOID\r
74 )\r
75{\r
76 EFI_STATUS Status;\r
77 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
78 UINT64 CurrentTick;\r
79 UINT32 TimerPeriod;\r
80\r
81 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);\r
82\r
83 if (EFI_ERROR (Status)) {\r
84 return Status;\r
85 }\r
86\r
87 Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, (UINT64 *) &TimerPeriod);\r
88\r
89 if (EFI_ERROR (Status)) {\r
90 //\r
91 // For NT32 Simulator only. 358049 is a similar value to keep timer granularity.\r
92 // Set the timer period by ourselves.\r
93 //\r
94 TimerPeriod = NTTIMERPERIOD;\r
95 }\r
96 //\r
97 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).\r
98 // So 1e+12 is divided by timer period to produce the freq in tick/ms.\r
99 //\r
100 mFrequency = (UINT32) DivU64x32 (1000000000000ULL, TimerPeriod);\r
101\r
102 return EFI_SUCCESS;\r
103}\r
104\r
105/**\r
106 Get and caculate the duration in ms.\r
107\r
108 @param[in] Begin The start point of time.\r
109 @param[in] End The end point of time.\r
110\r
111 @return The duration in ms.\r
112\r
113**/\r
114UINT32\r
115Ping6CalculateTick (\r
116 IN UINT64 Begin,\r
117 IN UINT64 End\r
118 )\r
119{\r
120 ASSERT (End > Begin);\r
121 return (UINT32) DivU64x32 (End - Begin, mFrequency);\r
122}\r
123\r
124/**\r
125 Destroy IPING6_ICMP6_TX_INFO, and recollect the memory.\r
126\r
127 @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO.\r
128\r
129**/\r
130VOID\r
131Ping6DestroyTxInfo (\r
132 IN PING6_ICMP6_TX_INFO *TxInfo\r
133 )\r
134{\r
135 EFI_IP6_TRANSMIT_DATA *TxData;\r
136 EFI_IP6_FRAGMENT_DATA *FragData;\r
137 UINTN Index;\r
138\r
139 ASSERT (TxInfo != NULL);\r
140\r
141 if (TxInfo->Token != NULL) {\r
142\r
143 if (TxInfo->Token->Event != NULL) {\r
144 gBS->CloseEvent (TxInfo->Token->Event);\r
145 }\r
146\r
147 TxData = TxInfo->Token->Packet.TxData;\r
148 if (TxData != NULL) {\r
149\r
150 if (TxData->OverrideData != NULL) {\r
151 FreePool (TxData->OverrideData);\r
152 }\r
153\r
154 if (TxData->ExtHdrs != NULL) {\r
155 FreePool (TxData->ExtHdrs);\r
156 }\r
157\r
158 for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
159 FragData = TxData->FragmentTable[Index].FragmentBuffer;\r
160 if (FragData != NULL) {\r
161 FreePool (FragData);\r
162 }\r
163 }\r
164 }\r
165\r
166 FreePool (TxInfo->Token);\r
167 }\r
168\r
169 FreePool (TxInfo);\r
170}\r
171\r
172/**\r
173 Match the request, and reply with SequenceNum/TimeStamp.\r
174\r
175 @param[in] Private The pointer to PING6_PRIVATE_DATA.\r
176 @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY.\r
177\r
178 @retval EFI_SUCCESS The match is successful.\r
179 @retval EFI_NOT_FOUND The reply can't be matched with any request.\r
180\r
181**/\r
182EFI_STATUS\r
183Ping6MatchEchoReply (\r
184 IN PING6_PRIVATE_DATA *Private,\r
185 IN ICMP6_ECHO_REQUEST_REPLY *Packet\r
186 )\r
187{\r
188 PING6_ICMP6_TX_INFO *TxInfo;\r
189 LIST_ENTRY *Entry;\r
190 LIST_ENTRY *NextEntry;\r
191\r
192 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
193 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
194\r
195 if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) {\r
196 Private->RxCount++;\r
197 RemoveEntryList (&TxInfo->Link);\r
198 Ping6DestroyTxInfo (TxInfo);\r
199 return EFI_SUCCESS;\r
200 }\r
201 }\r
202\r
203 return EFI_NOT_FOUND;\r
204}\r
205\r
206/**\r
207 The original intention is to send a request.\r
208 Currently, the application retransmits an icmp6 echo request packet\r
209 per second in sendnumber times that is specified by the user.\r
210 Because nothing can be done here, all things move to the timer rountine.\r
211\r
212 @param[in] Event A EFI_EVENT type event.\r
213 @param[in] Context The pointer to Context.\r
214\r
215**/\r
216VOID\r
217EFIAPI\r
218Ping6OnEchoRequestSent (\r
219 IN EFI_EVENT Event,\r
220 IN VOID *Context\r
221 )\r
222{\r
223}\r
224\r
225/**\r
226 receive reply, match and print reply infomation.\r
227\r
228 @param[in] Event A EFI_EVENT type event.\r
229 @param[in] Context The pointer to context.\r
230\r
231**/\r
232VOID\r
233EFIAPI\r
234Ping6OnEchoReplyReceived (\r
235 IN EFI_EVENT Event,\r
236 IN VOID *Context\r
237 )\r
238{\r
239 EFI_STATUS Status;\r
240 PING6_PRIVATE_DATA *Private;\r
241 EFI_IP6_COMPLETION_TOKEN *RxToken;\r
242 EFI_IP6_RECEIVE_DATA *RxData;\r
243 ICMP6_ECHO_REQUEST_REPLY *Reply;\r
244 UINT32 PayLoad;\r
245 UINT32 Rtt;\r
246 CHAR8 Near;\r
247\r
248 Private = (PING6_PRIVATE_DATA *) Context;\r
249\r
250 if (Private->Status == EFI_ABORTED) {\r
251 return;\r
252 }\r
253\r
254 RxToken = &Private->RxToken;\r
255 RxData = RxToken->Packet.RxData;\r
256 Reply = RxData->FragmentTable[0].FragmentBuffer;\r
257 PayLoad = RxData->DataLength;\r
258\r
259 if (RxData->Header->NextHeader != IP6_ICMP) {\r
260 goto ON_EXIT;\r
261 }\r
262\r
263 if (!IP6_IS_MULTICAST (&Private->DstAddress) && \r
264 !EFI_IP6_EQUAL (&RxData->Header->SourceAddress, &Private->DstAddress)) {\r
265 goto ON_EXIT;\r
266 }\r
267\r
268 if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) {\r
269 goto ON_EXIT;\r
270 }\r
271\r
272 if (PayLoad != Private->BufferSize) {\r
273 goto ON_EXIT;\r
274 }\r
275 //\r
276 // Check whether the reply matches the sent request before.\r
277 //\r
278 Status = Ping6MatchEchoReply (Private, Reply);\r
279 if (EFI_ERROR(Status)) {\r
280 goto ON_EXIT;\r
281 }\r
282 //\r
283 // Display statistics on this icmp6 echo reply packet.\r
284 //\r
285 Rtt = Ping6CalculateTick (Reply->TimeStamp, ReadTime ());\r
286 if (Rtt != 0) {\r
287 Near = (CHAR8) '=';\r
288 } else {\r
289 Near = (CHAR8) '<';\r
290 }\r
291\r
292 Private->RttSum += Rtt;\r
293 Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
294 Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax;\r
295\r
296 ShellPrintHiiEx (\r
297 -1,\r
298 -1,\r
299 NULL,\r
300 STRING_TOKEN (STR_PING6_REPLY_INFO),\r
301 mHiiHandle,\r
302 PayLoad,\r
303 mIp6DstString,\r
304 Reply->SequenceNum,\r
305 RxData->Header->HopLimit,\r
306 Near,\r
307 Rtt\r
308 );\r
309\r
310ON_EXIT:\r
311\r
312 if (Private->RxCount < Private->SendNum) {\r
313 //\r
314 // Continue to receive icmp6 echo reply packets.\r
315 //\r
316 RxToken->Status = EFI_ABORTED;\r
317\r
318 Status = Private->Ip6->Receive (Private->Ip6, RxToken);\r
319\r
320 if (EFI_ERROR (Status)) {\r
321 Private->Status = EFI_ABORTED;\r
322 }\r
323 } else {\r
324 //\r
325 // All reply have already been received from the dest host.\r
326 //\r
327 Private->Status = EFI_SUCCESS;\r
328 }\r
329 //\r
330 // Singal to recycle the each rxdata here, not at the end of process.\r
331 //\r
332 gBS->SignalEvent (RxData->RecycleSignal);\r
333}\r
334\r
335/**\r
336 Initial EFI_IP6_COMPLETION_TOKEN.\r
337\r
338 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
339 @param[in] TimeStamp The TimeStamp of request.\r
340 @param[in] SequenceNum The SequenceNum of request.\r
341\r
342 @return The pointer of EFI_IP6_COMPLETION_TOKEN.\r
343\r
344**/\r
345EFI_IP6_COMPLETION_TOKEN *\r
346Ping6GenerateToken (\r
347 IN PING6_PRIVATE_DATA *Private,\r
348 IN UINT64 TimeStamp,\r
349 IN UINT16 SequenceNum\r
350 )\r
351{\r
352 EFI_STATUS Status;\r
353 EFI_IP6_COMPLETION_TOKEN *Token;\r
354 EFI_IP6_TRANSMIT_DATA *TxData;\r
355 ICMP6_ECHO_REQUEST_REPLY *Request;\r
356\r
357 Request = AllocateZeroPool (Private->BufferSize);\r
358\r
359 if (Request == NULL) {\r
360 return NULL;\r
361 }\r
362 //\r
363 // Assembly icmp6 echo request packet.\r
364 //\r
365 Request->Type = ICMP_V6_ECHO_REQUEST;\r
366 Request->Code = 0;\r
367 Request->SequenceNum = SequenceNum;\r
368 Request->TimeStamp = TimeStamp;\r
369 Request->Identifier = 0;\r
370 //\r
371 // Leave check sum to ip6 layer, since it has no idea of source address\r
372 // selection.\r
373 //\r
374 Request->Checksum = 0;\r
375\r
376 TxData = AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA));\r
377\r
378 if (TxData == NULL) {\r
379 FreePool (Request);\r
380 return NULL;\r
381 }\r
382 //\r
383 // Assembly ipv6 token for transmit.\r
384 //\r
385 TxData->OverrideData = 0;\r
386 TxData->ExtHdrsLength = 0;\r
387 TxData->ExtHdrs = NULL;\r
388 TxData->DataLength = Private->BufferSize;\r
389 TxData->FragmentCount = 1;\r
390 TxData->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
391 TxData->FragmentTable[0].FragmentLength = Private->BufferSize;\r
392\r
393 Token = AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN));\r
394\r
395 if (Token == NULL) {\r
396 FreePool (Request);\r
397 FreePool (TxData);\r
398 return NULL;\r
399 }\r
400\r
401 Token->Status = EFI_ABORTED;\r
402 Token->Packet.TxData = TxData;\r
403\r
404 Status = gBS->CreateEvent (\r
405 EVT_NOTIFY_SIGNAL,\r
406 TPL_CALLBACK,\r
407 Ping6OnEchoRequestSent,\r
408 Private,\r
409 &Token->Event\r
410 );\r
411\r
412 if (EFI_ERROR (Status)) {\r
413 FreePool (Request);\r
414 FreePool (TxData);\r
415 FreePool (Token);\r
416 return NULL;\r
417 }\r
418\r
419 return Token;\r
420}\r
421\r
422/**\r
423 Transmit the EFI_IP6_COMPLETION_TOKEN.\r
424\r
425 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
426\r
427 @retval EFI_SUCCESS Transmitted successfully.\r
428 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
429 @retval others Transmitted unsuccessfully.\r
430\r
431**/\r
432EFI_STATUS\r
433Ping6SendEchoRequest (\r
434 IN PING6_PRIVATE_DATA *Private\r
435 )\r
436{\r
437 EFI_STATUS Status;\r
438 PING6_ICMP6_TX_INFO *TxInfo;\r
439\r
440 TxInfo = AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO));\r
441\r
442 if (TxInfo == NULL) {\r
443 return EFI_OUT_OF_RESOURCES;\r
444 }\r
445\r
446 TxInfo->TimeStamp = ReadTime ();\r
447 TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
448\r
449 TxInfo->Token = Ping6GenerateToken (\r
450 Private,\r
451 TxInfo->TimeStamp,\r
452 TxInfo->SequenceNum\r
453 );\r
454\r
455 if (TxInfo->Token == NULL) {\r
456 Ping6DestroyTxInfo (TxInfo);\r
457 return EFI_OUT_OF_RESOURCES;\r
458 }\r
459\r
460 Status = Private->Ip6->Transmit (Private->Ip6, TxInfo->Token);\r
461\r
462 if (EFI_ERROR (Status)) {\r
463 Ping6DestroyTxInfo (TxInfo);\r
464 return Status;\r
465 }\r
466\r
467 InsertTailList (&Private->TxList, &TxInfo->Link);\r
468 Private->TxCount++;\r
469\r
470 return EFI_SUCCESS;\r
471}\r
472\r
473/**\r
474 Place a completion token into the receive packet queue to receive the echo reply.\r
475\r
476 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
477\r
478 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
479 @retval others Put the token into the receive packet queue unsuccessfully.\r
480\r
481**/\r
482EFI_STATUS\r
483Ping6ReceiveEchoReply (\r
484 IN PING6_PRIVATE_DATA *Private\r
485 )\r
486{\r
487 EFI_STATUS Status;\r
488\r
489 ZeroMem (&Private->RxToken, sizeof (EFI_IP6_COMPLETION_TOKEN));\r
490\r
491 Status = gBS->CreateEvent (\r
492 EVT_NOTIFY_SIGNAL,\r
493 TPL_CALLBACK,\r
494 Ping6OnEchoReplyReceived,\r
495 Private,\r
496 &Private->RxToken.Event\r
497 );\r
498\r
499 if (EFI_ERROR (Status)) {\r
500 return Status;\r
501 }\r
502\r
503 Private->RxToken.Status = EFI_NOT_READY;\r
504\r
505 return Private->Ip6->Receive (Private->Ip6, &Private->RxToken);\r
506}\r
507\r
508/**\r
509 Remove the timeout request from the list.\r
510\r
511 @param[in] Event A EFI_EVENT type event.\r
512 @param[in] Context The pointer to Context.\r
513\r
514**/\r
515VOID\r
516EFIAPI\r
517Ping6OnTimerRoutine (\r
518 IN EFI_EVENT Event,\r
519 IN VOID *Context\r
520 )\r
521{\r
522 EFI_STATUS Status;\r
523 PING6_PRIVATE_DATA *Private;\r
524 PING6_ICMP6_TX_INFO *TxInfo;\r
525 LIST_ENTRY *Entry;\r
526 LIST_ENTRY *NextEntry;\r
527 UINT32 Time;\r
528\r
529 Private = (PING6_PRIVATE_DATA *) Context;\r
530\r
531 //\r
532 // Retransmit icmp6 echo request packets per second in sendnumber times.\r
533 //\r
534 if (Private->TxCount < Private->SendNum) {\r
535\r
536 Status = Ping6SendEchoRequest (Private);\r
537 if (Private->TxCount != 0){\r
538 if (EFI_ERROR (Status)) {\r
539 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SEND_REQUEST), mHiiHandle, Private->TxCount + 1);\r
540 }\r
541 }\r
542 }\r
543 //\r
544 // Check whether any icmp6 echo request in the list timeout.\r
545 //\r
546 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
547 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
548 Time = Ping6CalculateTick (TxInfo->TimeStamp, ReadTime ());\r
549\r
550 //\r
551 // Remove the timeout echo request from txlist.\r
552 //\r
553 if (Time > PING6_DEFAULT_TIMEOUT) {\r
554\r
555 if (EFI_ERROR (TxInfo->Token->Status)) {\r
556 Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
557 }\r
558 //\r
559 // Remove the timeout icmp6 echo request from list.\r
560 //\r
561 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_TIMEOUT), mHiiHandle, TxInfo->SequenceNum);\r
562\r
563 RemoveEntryList (&TxInfo->Link);\r
564 Ping6DestroyTxInfo (TxInfo);\r
565\r
566 if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
567 //\r
568 // All the left icmp6 echo request in the list timeout.\r
569 //\r
570 Private->Status = EFI_TIMEOUT;\r
571 }\r
572 }\r
573 }\r
574}\r
575\r
576/**\r
577 Create a valid IP6 instance.\r
578\r
579 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
580\r
581 @retval EFI_SUCCESS Create a valid IP6 instance successfully.\r
582 @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully.\r
583 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address.\r
584 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
585 @retval EFI_NOT_FOUND The source address is not found.\r
586**/\r
587EFI_STATUS\r
588Ping6CreateIp6Instance (\r
589 IN PING6_PRIVATE_DATA *Private\r
590 )\r
591{\r
592 EFI_STATUS Status;\r
593 UINTN HandleIndex;\r
594 UINTN HandleNum;\r
595 EFI_HANDLE *HandleBuffer;\r
596 EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb;\r
597 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
598 EFI_IP6_CONFIG_DATA Ip6Config;\r
599 EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;\r
600 UINTN IfInfoSize;\r
601 EFI_IPv6_ADDRESS *Addr;\r
602 UINTN AddrIndex;\r
603\r
604 HandleBuffer = NULL;\r
605 Ip6Sb = NULL;\r
606 IfInfo = NULL;\r
607 IfInfoSize = 0;\r
608\r
609 //\r
610 // Locate all the handles with ip6 service binding protocol.\r
611 //\r
612 Status = gBS->LocateHandleBuffer (\r
613 ByProtocol,\r
614 &gEfiIp6ServiceBindingProtocolGuid,\r
615 NULL,\r
616 &HandleNum,\r
617 &HandleBuffer\r
618 );\r
619 if (EFI_ERROR (Status) || (HandleNum == 0)) {\r
620 return EFI_ABORTED;\r
621 }\r
622 //\r
623 // Source address is required when pinging a link-local address on multi-\r
624 // interfaces host.\r
625 //\r
626 if (NetIp6IsLinkLocalAddr (&Private->DstAddress) &&\r
627 NetIp6IsUnspecifiedAddr (&Private->SrcAddress) &&\r
628 (HandleNum > 1)) {\r
629 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), mHiiHandle);\r
630 Status = EFI_INVALID_PARAMETER;\r
631 goto ON_ERROR;\r
632 }\r
633 //\r
634 // For each ip6 protocol, check interface addresses list.\r
635 //\r
636 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
637\r
638 Ip6Sb = NULL;\r
639 IfInfo = NULL;\r
640 IfInfoSize = 0;\r
641\r
642 Status = gBS->HandleProtocol (\r
643 HandleBuffer[HandleIndex],\r
644 &gEfiIp6ServiceBindingProtocolGuid,\r
645 (VOID **) &Ip6Sb\r
646 );\r
647 if (EFI_ERROR (Status)) {\r
648 goto ON_ERROR;\r
649 }\r
650\r
651 if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) {\r
652 //\r
653 // No need to match interface address.\r
654 //\r
655 break;\r
656 } else {\r
657 //\r
658 // Ip6config protocol and ip6 service binding protocol are installed\r
659 // on the same handle.\r
660 //\r
661 Status = gBS->HandleProtocol (\r
662 HandleBuffer[HandleIndex],\r
663 &gEfiIp6ConfigProtocolGuid,\r
664 (VOID **) &Ip6Cfg\r
665 );\r
666\r
667 if (EFI_ERROR (Status)) {\r
668 goto ON_ERROR;\r
669 }\r
670 //\r
671 // Get the interface information size.\r
672 //\r
673 Status = Ip6Cfg->GetData (\r
674 Ip6Cfg,\r
675 Ip6ConfigDataTypeInterfaceInfo,\r
676 &IfInfoSize,\r
677 NULL\r
678 );\r
679\r
680 if (Status != EFI_BUFFER_TOO_SMALL) {\r
681 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), mHiiHandle, Status);\r
682 goto ON_ERROR;\r
683 }\r
684\r
685 IfInfo = AllocateZeroPool (IfInfoSize);\r
686\r
687 if (IfInfo == NULL) {\r
688 Status = EFI_OUT_OF_RESOURCES;\r
689 goto ON_ERROR;\r
690 }\r
691 //\r
692 // Get the interface info.\r
693 //\r
694 Status = Ip6Cfg->GetData (\r
695 Ip6Cfg,\r
696 Ip6ConfigDataTypeInterfaceInfo,\r
697 &IfInfoSize,\r
698 IfInfo\r
699 );\r
700\r
701 if (EFI_ERROR (Status)) {\r
702 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), mHiiHandle, Status);\r
703 goto ON_ERROR;\r
704 }\r
705 //\r
706 // Check whether the source address is one of the interface addresses.\r
707 //\r
708 for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) {\r
709\r
710 Addr = &(IfInfo->AddressInfo[AddrIndex].Address);\r
711 if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
712 //\r
713 // Match a certain interface address.\r
714 //\r
715 break;\r
716 }\r
717 }\r
718\r
719 if (AddrIndex < IfInfo->AddressInfoCount) {\r
720 //\r
721 // Found a nic handle with right interface address.\r
722 //\r
723 break;\r
724 }\r
725 }\r
726\r
727 FreePool (IfInfo);\r
728 IfInfo = NULL;\r
729 }\r
730 //\r
731 // No exact interface address matched.\r
732 //\r
733\r
734 if (HandleIndex == HandleNum) {\r
735 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND), mHiiHandle, mIp6SrcString);\r
736 Status = EFI_NOT_FOUND;\r
737 goto ON_ERROR;\r
738 }\r
739\r
740 Private->NicHandle = HandleBuffer[HandleIndex];\r
741\r
742 ASSERT (Ip6Sb != NULL);\r
743 Status = Ip6Sb->CreateChild (Ip6Sb, &Private->Ip6ChildHandle);\r
744\r
745 if (EFI_ERROR (Status)) {\r
746 goto ON_ERROR;\r
747 }\r
748\r
749 Status = gBS->OpenProtocol (\r
750 Private->Ip6ChildHandle,\r
751 &gEfiIp6ProtocolGuid,\r
752 (VOID **) &Private->Ip6,\r
753 Private->ImageHandle,\r
754 Private->Ip6ChildHandle,\r
755 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
756 );\r
757 if (EFI_ERROR (Status)) {\r
758 goto ON_ERROR;\r
759 }\r
760\r
761 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
762\r
763 //\r
764 // Configure the ip6 instance for icmp6 packet exchange.\r
765 //\r
766 Ip6Config.DefaultProtocol = 58;\r
767 Ip6Config.AcceptAnyProtocol = FALSE;\r
768 Ip6Config.AcceptIcmpErrors = TRUE;\r
769 Ip6Config.AcceptPromiscuous = FALSE;\r
770 Ip6Config.TrafficClass = 0;\r
771 Ip6Config.HopLimit = 128;\r
772 Ip6Config.FlowLabel = 0;\r
773 Ip6Config.ReceiveTimeout = 0;\r
774 Ip6Config.TransmitTimeout = 0;\r
775\r
776 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
777\r
778 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
779\r
780 Status = Private->Ip6->Configure (Private->Ip6, &Ip6Config);\r
781\r
782 if (EFI_ERROR (Status)) {\r
783 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_CONFIG), mHiiHandle, Status);\r
784 goto ON_ERROR;\r
785 }\r
786\r
787 return EFI_SUCCESS;\r
788\r
789ON_ERROR:\r
790 if (HandleBuffer != NULL) {\r
791 FreePool (HandleBuffer);\r
792 }\r
793\r
794 if (IfInfo != NULL) {\r
795 FreePool (IfInfo);\r
796 }\r
797\r
798 if ((Ip6Sb != NULL) && (Private->Ip6ChildHandle != NULL)) {\r
799 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
800 }\r
801\r
802 return Status;\r
803}\r
804\r
805/**\r
806 Destory the IP6 instance.\r
807\r
808 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
809\r
810**/\r
811VOID\r
812Ping6DestoryIp6Instance (\r
813 IN PING6_PRIVATE_DATA *Private\r
814 )\r
815{\r
816 EFI_STATUS Status;\r
817 EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb;\r
818\r
819 gBS->CloseProtocol (\r
820 Private->Ip6ChildHandle,\r
821 &gEfiIp6ProtocolGuid,\r
822 Private->ImageHandle,\r
823 Private->Ip6ChildHandle\r
824 );\r
825\r
826 Status = gBS->HandleProtocol (\r
827 Private->NicHandle,\r
828 &gEfiIp6ServiceBindingProtocolGuid,\r
829 (VOID **) &Ip6Sb\r
830 );\r
831\r
832 if (!EFI_ERROR(Status)) {\r
833 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
834 }\r
835}\r
836\r
837/**\r
838 The Ping6 Process.\r
839\r
840 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
841 @param[in] SendNumber The send request count.\r
842 @param[in] BufferSize The send buffer size.\r
843 @param[in] SrcAddress The source IPv6 address.\r
844 @param[in] DstAddress The destination IPv6 address.\r
845\r
846 @retval EFI_SUCCESS The ping6 processed successfullly.\r
847 @retval others The ping6 processed unsuccessfully.\r
848\r
849**/\r
850EFI_STATUS\r
851Ping6 (\r
852 IN EFI_HANDLE ImageHandle,\r
853 IN UINT32 SendNumber,\r
854 IN UINT32 BufferSize,\r
855 IN EFI_IPv6_ADDRESS *SrcAddress,\r
856 IN EFI_IPv6_ADDRESS *DstAddress\r
857 )\r
858{\r
859 EFI_STATUS Status;\r
860 EFI_INPUT_KEY Key;\r
861 PING6_PRIVATE_DATA *Private;\r
862 PING6_ICMP6_TX_INFO *TxInfo;\r
863 LIST_ENTRY *Entry;\r
864 LIST_ENTRY *NextEntry;\r
865\r
866 Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA));\r
867\r
868 ASSERT (Private != NULL);\r
869\r
870 Private->ImageHandle = ImageHandle;\r
871 Private->SendNum = SendNumber;\r
872 Private->BufferSize = BufferSize;\r
873 Private->RttMin = 0xFFFF;\r
874 Private->Status = EFI_NOT_READY;\r
875\r
876 InitializeListHead (&Private->TxList);\r
877\r
878 IP6_COPY_ADDRESS (&Private->SrcAddress, SrcAddress);\r
879 IP6_COPY_ADDRESS (&Private->DstAddress, DstAddress);\r
880\r
881 //\r
882 // Open and configure a ip6 instance for ping6.\r
883 //\r
884 Status = Ping6CreateIp6Instance (Private);\r
885\r
886 if (EFI_ERROR (Status)) {\r
887 goto ON_EXIT;\r
888 }\r
889 //\r
890 // Print the command line itself.\r
891 //\r
892 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_START), mHiiHandle, mIp6DstString, Private->BufferSize);\r
893 //\r
894 // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
895 //\r
896 Status = Ping6ReceiveEchoReply (Private);\r
897\r
898 if (EFI_ERROR (Status)) {\r
899 goto ON_EXIT;\r
900 }\r
901 //\r
902 // Create and start timer to send icmp6 echo request packet per second.\r
903 //\r
904 Status = gBS->CreateEvent (\r
905 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
906 TPL_CALLBACK,\r
907 Ping6OnTimerRoutine,\r
908 Private,\r
909 &Private->Timer\r
910 );\r
911\r
912 if (EFI_ERROR (Status)) {\r
913 goto ON_EXIT;\r
914 }\r
915 //\r
916 // Create a ipv6 token to send the first icmp6 echo request packet.\r
917 //\r
918 Status = Ping6SendEchoRequest (Private);\r
919 //\r
920 // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
921 //\r
922 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
923 if(Status == EFI_NOT_FOUND) {\r
924 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN), mHiiHandle, mIp6DstString);\r
925 }\r
926\r
927 goto ON_EXIT;\r
928 }\r
929\r
930 Status = gBS->SetTimer (\r
931 Private->Timer,\r
932 TimerPeriodic,\r
933 PING6_ONE_SECOND\r
934 );\r
935\r
936 if (EFI_ERROR (Status)) {\r
937 goto ON_EXIT;\r
938 }\r
939 //\r
940 // Control the ping6 process by two factors:\r
941 // 1. Hot key\r
942 // 2. Private->Status\r
943 // 2.1. success means all icmp6 echo request packets get reply packets.\r
944 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
945 // 2.3. noready means ping6 process is on-the-go.\r
946 //\r
947 while (Private->Status == EFI_NOT_READY) {\r
948 Private->Ip6->Poll (Private->Ip6);\r
949\r
950 //\r
951 // Terminate the ping6 process by 'esc' or 'ctl-c'.\r
952 //\r
953 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
954\r
955 if (!EFI_ERROR(Status)) {\r
956 if ((Key.UnicodeChar == 0x1b) || (Key.UnicodeChar == 0x03) ||\r
957 ((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_ESC))) {\r
958 goto ON_STAT;\r
959 }\r
960 }\r
961 }\r
962\r
963ON_STAT:\r
964 //\r
965 // Display the statistics in all.\r
966 //\r
967 gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
968\r
969 if (Private->TxCount != 0) {\r
970 ShellPrintHiiEx (\r
971 -1,\r
972 -1,\r
973 NULL,\r
974 STRING_TOKEN (STR_PING6_STAT),\r
975 mHiiHandle,\r
976 Private->TxCount,\r
977 Private->RxCount,\r
978 (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,\r
979 Private->RttSum\r
980 );\r
981 }\r
982\r
983 if (Private->RxCount != 0) {\r
984 ShellPrintHiiEx (\r
985 -1,\r
986 -1,\r
987 NULL,\r
988 STRING_TOKEN (STR_PING6_RTT),\r
989 mHiiHandle,\r
990 Private->RttMin,\r
991 Private->RttMax,\r
992 Private->RttSum / Private->RxCount\r
993 );\r
994 }\r
995\r
996ON_EXIT:\r
997\r
998 if (Private != NULL) {\r
999 Private->Status = EFI_ABORTED;\r
1000\r
1001 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
1002 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
1003\r
1004 Status = Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
1005\r
1006 RemoveEntryList (&TxInfo->Link);\r
1007 Ping6DestroyTxInfo (TxInfo);\r
1008 }\r
1009\r
1010 if (Private->Timer != NULL) {\r
1011 gBS->CloseEvent (Private->Timer);\r
1012 }\r
1013\r
1014 if (Private->Ip6 != NULL) {\r
1015 Status = Private->Ip6->Cancel (Private->Ip6, &Private->RxToken);\r
1016 }\r
1017\r
1018 if (Private->RxToken.Event != NULL) {\r
1019 gBS->CloseEvent (Private->RxToken.Event);\r
1020 }\r
1021\r
1022 if (Private->Ip6ChildHandle != NULL) {\r
1023 Ping6DestoryIp6Instance (Private);\r
1024 }\r
1025\r
1026 FreePool (Private);\r
1027 }\r
1028\r
1029 return Status;\r
1030}\r
1031\r
1032/**\r
1033 This is the declaration of an EFI image entry point. This entry point is\r
1034 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including\r
1035 both device drivers and bus drivers.\r
1036\r
1037 The entry point for the Ping6 application that parses the command line input and calls the Ping6 process.\r
1038\r
1039 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
1040 @param[in] SystemTable A pointer to the EFI System Table.\r
1041\r
1042 @retval EFI_SUCCESS The operation completed successfully.\r
1043 @retval EFI_INVALID_PARAMETETR Input parameters combination is invalid.\r
1044 @retval Others Some errors occur.\r
1045\r
1046**/\r
1047EFI_STATUS\r
1048EFIAPI\r
1049InitializePing6 (\r
1050 IN EFI_HANDLE ImageHandle,\r
1051 IN EFI_SYSTEM_TABLE *SystemTable\r
1052 )\r
1053{\r
1054 EFI_STATUS Status;\r
1055 EFI_IPv6_ADDRESS DstAddress;\r
1056 EFI_IPv6_ADDRESS SrcAddress;\r
1057 UINT64 BufferSize;\r
1058 UINTN SendNumber;\r
1059 LIST_ENTRY *ParamPackage;\r
1060 CONST CHAR16 *ValueStr;\r
1061 CONST CHAR16 *ValueStrPtr;\r
1062 UINTN NonOptionCount;\r
1063\r
1064 //\r
1065 // Register our string package with HII and return the handle to it.\r
1066 //\r
1067 mHiiHandle = HiiAddPackages (&gEfiCallerIdGuid, ImageHandle, Ping6Strings, NULL);\r
1068 ASSERT (mHiiHandle != NULL);\r
1069\r
1070 Status = ShellCommandLineParseEx (Ping6ParamList, &ParamPackage, NULL, TRUE, FALSE);\r
1071 if (EFI_ERROR(Status)) {\r
1072 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), mHiiHandle);\r
1073 goto ON_EXIT;\r
1074 }\r
1075\r
1076 if (ShellCommandLineGetFlag (ParamPackage, L"-?")) {\r
1077 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_HELP), mHiiHandle);\r
1078 goto ON_EXIT;\r
1079 }\r
1080\r
1081 SendNumber = 10;\r
1082 BufferSize = 16;\r
1083\r
1084 //\r
1085 // Parse the paramter of count number.\r
1086 //\r
1087 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
1088 ValueStrPtr = ValueStr;\r
1089 if (ValueStr != NULL) {\r
1090 SendNumber = ShellStrToUintn (ValueStrPtr);\r
1091\r
1092 //\r
1093 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1094 //\r
1095 if ((SendNumber == 0) || (SendNumber > PING6_MAX_SEND_NUMBER)) {\r
1096 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER), mHiiHandle, ValueStr);\r
1097 Status = EFI_INVALID_PARAMETER;\r
1098 goto ON_EXIT;\r
1099 }\r
1100 }\r
1101 //\r
1102 // Parse the paramter of buffer size.\r
1103 //\r
1104 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
1105 ValueStrPtr = ValueStr;\r
1106 if (ValueStr != NULL) {\r
1107 BufferSize = ShellStrToUintn (ValueStrPtr);\r
1108\r
1109 //\r
1110 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1111 //\r
1112 if ((BufferSize < 16) || (BufferSize > PING6_MAX_BUFFER_SIZE)) {\r
1113 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE), mHiiHandle, ValueStr);\r
1114 Status = EFI_INVALID_PARAMETER;\r
1115 goto ON_EXIT;\r
1116 }\r
1117 }\r
1118\r
1119 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
1120 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
1121\r
1122 //\r
1123 // Parse the paramter of source ip address.\r
1124 //\r
1125 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
1126 ValueStrPtr = ValueStr;\r
1127 if (ValueStr != NULL) {\r
1128 mIp6SrcString = ValueStr;\r
1129 Status = NetLibStrToIp6 (ValueStrPtr, &SrcAddress);\r
1130 if (EFI_ERROR (Status)) {\r
1131 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), mHiiHandle, ValueStr);\r
1132 Status = EFI_INVALID_PARAMETER;\r
1133 goto ON_EXIT;\r
1134 }\r
1135 }\r
1136 //\r
1137 // Parse the paramter of destination ip address.\r
1138 //\r
780847d1 1139 NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
a3bcde70
HT
1140 ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1));\r
1141 if (NonOptionCount != 2) {\r
1142 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), mHiiHandle);\r
1143 Status = EFI_INVALID_PARAMETER;\r
1144 goto ON_EXIT;\r
1145 }\r
1146 ValueStrPtr = ValueStr;\r
1147 if (ValueStr != NULL) {\r
1148 mIp6DstString = ValueStr;\r
1149 Status = NetLibStrToIp6 (ValueStrPtr, &DstAddress);\r
1150 if (EFI_ERROR (Status)) {\r
1151 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), mHiiHandle, ValueStr);\r
1152 Status = EFI_INVALID_PARAMETER;\r
1153 goto ON_EXIT;\r
1154 }\r
1155 }\r
1156 //\r
1157 // Get frequency to calculate the time from ticks.\r
1158 //\r
1159 Status = Ping6GetFrequency ();\r
1160\r
1161 if (EFI_ERROR(Status)) {\r
1162 goto ON_EXIT;\r
1163 }\r
1164 //\r
1165 // Enter into ping6 process.\r
1166 //\r
1167 Status = Ping6 (\r
1168 ImageHandle,\r
1169 (UINT32)SendNumber,\r
1170 (UINT32)BufferSize,\r
1171 &SrcAddress,\r
1172 &DstAddress\r
1173 );\r
1174\r
1175ON_EXIT:\r
1176 ShellCommandLineFreeVarList (ParamPackage);\r
1177 HiiRemovePackages (mHiiHandle);\r
1178 return Status;\r
1179}\r