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