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