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