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