]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c
ShellPkg: Update header file including style
[mirror_edk2.git] / ShellPkg / Library / UefiShellNetwork2CommandsLib / Ping6.c
CommitLineData
43ca1753
ZL
1/** @file\r
2 The implementation for Ping6 application.\r
3\r
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php.\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "UefiShellNetwork2CommandsLib.h"\r
17\r
18#define PING6_DEFAULT_TIMEOUT 5000\r
19#define PING6_MAX_SEND_NUMBER 10000\r
20#define PING6_MAX_BUFFER_SIZE 32768\r
21#define PING6_ONE_SECOND 10000000\r
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
ZL
52 UINT32 TimerPeriod;\r
53 UINT32 RttTimerTick; \r
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
202 \r
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
248 \r
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
477 Private->Status = EFI_ABORTED;\r
478 }\r
479 } else {\r
480 //\r
481 // All reply have already been received from the dest host.\r
482 //\r
483 Private->Status = EFI_SUCCESS;\r
484 }\r
485 //\r
486 // Singal to recycle the each rxdata here, not at the end of process.\r
487 //\r
488 gBS->SignalEvent (RxData->RecycleSignal);\r
489}\r
490\r
491/**\r
492 Initial EFI_IP6_COMPLETION_TOKEN.\r
493\r
494 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
495 @param[in] TimeStamp The TimeStamp of request.\r
496 @param[in] SequenceNum The SequenceNum of request.\r
497\r
498 @return The pointer of EFI_IP6_COMPLETION_TOKEN.\r
499\r
500**/\r
501EFI_IP6_COMPLETION_TOKEN *\r
502Ping6GenerateToken (\r
503 IN PING6_PRIVATE_DATA *Private,\r
825f09b7 504 IN UINT32 TimeStamp,\r
43ca1753
ZL
505 IN UINT16 SequenceNum\r
506 )\r
507{\r
508 EFI_STATUS Status;\r
509 EFI_IP6_COMPLETION_TOKEN *Token;\r
510 EFI_IP6_TRANSMIT_DATA *TxData;\r
511 ICMP6_ECHO_REQUEST_REPLY *Request;\r
512\r
513 Request = AllocateZeroPool (Private->BufferSize);\r
514\r
515 if (Request == NULL) {\r
516 return NULL;\r
517 }\r
518 //\r
519 // Assembly icmp6 echo request packet.\r
520 //\r
521 Request->Type = ICMP_V6_ECHO_REQUEST;\r
522 Request->Code = 0;\r
523 Request->SequenceNum = SequenceNum;\r
524 Request->TimeStamp = TimeStamp;\r
525 Request->Identifier = 0;\r
526 //\r
527 // Leave check sum to ip6 layer, since it has no idea of source address\r
528 // selection.\r
529 //\r
530 Request->Checksum = 0;\r
531\r
532 TxData = AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA));\r
533\r
534 if (TxData == NULL) {\r
535 FreePool (Request);\r
536 return NULL;\r
537 }\r
538 //\r
539 // Assembly ipv6 token for transmit.\r
540 //\r
541 TxData->OverrideData = 0;\r
542 TxData->ExtHdrsLength = 0;\r
543 TxData->ExtHdrs = NULL;\r
544 TxData->DataLength = Private->BufferSize;\r
545 TxData->FragmentCount = 1;\r
546 TxData->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
547 TxData->FragmentTable[0].FragmentLength = Private->BufferSize;\r
548\r
549 Token = AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN));\r
550\r
551 if (Token == NULL) {\r
552 FreePool (Request);\r
553 FreePool (TxData);\r
554 return NULL;\r
555 }\r
556\r
557 Token->Status = EFI_ABORTED;\r
558 Token->Packet.TxData = TxData;\r
559\r
560 Status = gBS->CreateEvent (\r
561 EVT_NOTIFY_SIGNAL,\r
562 TPL_CALLBACK,\r
563 Ping6OnEchoRequestSent6,\r
564 Private,\r
565 &Token->Event\r
566 );\r
567\r
568 if (EFI_ERROR (Status)) {\r
569 FreePool (Request);\r
570 FreePool (TxData);\r
571 FreePool (Token);\r
572 return NULL;\r
573 }\r
574\r
575 return Token;\r
576}\r
577\r
578/**\r
579 Transmit the EFI_IP6_COMPLETION_TOKEN.\r
580\r
581 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
582\r
583 @retval EFI_SUCCESS Transmitted successfully.\r
584 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
585 @retval others Transmitted unsuccessfully.\r
586\r
587**/\r
588EFI_STATUS\r
589Ping6SendEchoRequest (\r
590 IN PING6_PRIVATE_DATA *Private\r
591 )\r
592{\r
593 EFI_STATUS Status;\r
594 PING6_ICMP6_TX_INFO *TxInfo;\r
595\r
596 TxInfo = AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO));\r
597\r
598 if (TxInfo == NULL) {\r
599 return EFI_OUT_OF_RESOURCES;\r
600 }\r
601\r
825f09b7 602 TxInfo->TimeStamp = Ping6ReadTime (Private);\r
43ca1753
ZL
603 TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
604\r
605 TxInfo->Token = Ping6GenerateToken (\r
606 Private,\r
607 TxInfo->TimeStamp,\r
608 TxInfo->SequenceNum\r
609 );\r
610\r
611 if (TxInfo->Token == NULL) {\r
612 Ping6DestroyTxInfo (TxInfo);\r
613 return EFI_OUT_OF_RESOURCES;\r
614 }\r
615\r
616 Status = Private->Ip6->Transmit (Private->Ip6, TxInfo->Token);\r
617\r
618 if (EFI_ERROR (Status)) {\r
619 Ping6DestroyTxInfo (TxInfo);\r
620 return Status;\r
621 }\r
622\r
623 InsertTailList (&Private->TxList, &TxInfo->Link);\r
624 Private->TxCount++;\r
625\r
626 return EFI_SUCCESS;\r
627}\r
628\r
629/**\r
630 Place a completion token into the receive packet queue to receive the echo reply.\r
631\r
632 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
633\r
634 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
635 @retval others Put the token into the receive packet queue unsuccessfully.\r
636\r
637**/\r
638EFI_STATUS\r
639Ping6OnReceiveEchoReply (\r
640 IN PING6_PRIVATE_DATA *Private\r
641 )\r
642{\r
643 EFI_STATUS Status;\r
644\r
645 ZeroMem (&Private->RxToken, sizeof (EFI_IP6_COMPLETION_TOKEN));\r
646\r
647 Status = gBS->CreateEvent (\r
648 EVT_NOTIFY_SIGNAL,\r
649 TPL_CALLBACK,\r
650 Ping6OnEchoReplyReceived6,\r
651 Private,\r
652 &Private->RxToken.Event\r
653 );\r
654\r
655 if (EFI_ERROR (Status)) {\r
656 return Status;\r
657 }\r
658\r
659 Private->RxToken.Status = EFI_NOT_READY;\r
660\r
661 return Private->Ip6->Receive (Private->Ip6, &Private->RxToken);\r
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
674 IN EFI_EVENT Event,\r
675 IN VOID *Context\r
676 )\r
677{\r
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
684\r
685 Private = (PING6_PRIVATE_DATA *) Context;\r
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
691\r
692 Status = Ping6SendEchoRequest (Private);\r
693 if (Private->TxCount != 0){\r
694 if (EFI_ERROR (Status)) {\r
695 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SEND_REQUEST), gShellNetwork2HiiHandle, Private->TxCount + 1);\r
696 }\r
697 }\r
698 }\r
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
710\r
711 if (EFI_ERROR (TxInfo->Token->Status)) {\r
712 Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
713 }\r
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
745 IN PING6_PRIVATE_DATA *Private\r
746 )\r
747{\r
748 EFI_STATUS Status;\r
749 UINTN HandleIndex;\r
750 UINTN HandleNum;\r
751 EFI_HANDLE *HandleBuffer;\r
76cd3ffa
JW
752 BOOLEAN UnspecifiedSrc;\r
753 BOOLEAN MediaPresent;\r
43ca1753
ZL
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
76cd3ffa
JW
762 HandleBuffer = NULL;\r
763 UnspecifiedSrc = FALSE;\r
764 MediaPresent = TRUE;\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
785 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected. \r
786 //\r
787 UnspecifiedSrc = TRUE;\r
788 }\r
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
76cd3ffa 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
803\r
804 Ip6Sb = NULL;\r
805 IfInfo = NULL;\r
806 IfInfoSize = 0;\r
807\r
76cd3ffa
JW
808 if (UnspecifiedSrc) {\r
809 //\r
810 // Check media.\r
811 //\r
812 NetLibDetectMedia (HandleBuffer[HandleIndex], &MediaPresent);\r
813 if (!MediaPresent) {\r
814 //\r
815 // Skip this one.\r
816 //\r
817 continue;\r
818 }\r
819 }\r
820\r
43ca1753
ZL
821 Status = gBS->HandleProtocol (\r
822 HandleBuffer[HandleIndex],\r
823 &gEfiIp6ServiceBindingProtocolGuid,\r
824 (VOID **) &Ip6Sb\r
825 );\r
826 if (EFI_ERROR (Status)) {\r
827 goto ON_ERROR;\r
828 }\r
829\r
76cd3ffa
JW
830 //\r
831 // Ip6config protocol and ip6 service binding protocol are installed\r
832 // on the same handle.\r
833 //\r
834 Status = gBS->HandleProtocol (\r
835 HandleBuffer[HandleIndex],\r
836 &gEfiIp6ConfigProtocolGuid,\r
837 (VOID **) &Ip6Cfg\r
838 );\r
43ca1753 839\r
76cd3ffa
JW
840 if (EFI_ERROR (Status)) {\r
841 goto ON_ERROR;\r
842 }\r
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
864 //\r
865 // Get the interface info.\r
866 //\r
867 Status = Ip6Cfg->GetData (\r
868 Ip6Cfg,\r
869 Ip6ConfigDataTypeInterfaceInfo,\r
870 &IfInfoSize,\r
871 IfInfo\r
872 );\r
43ca1753 873\r
76cd3ffa
JW
874 if (EFI_ERROR (Status)) {\r
875 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);\r
876 goto ON_ERROR;\r
877 }\r
878 //\r
879 // Check whether the source address is one of the interface addresses.\r
880 //\r
881 for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) {\r
882 Addr = &(IfInfo->AddressInfo[AddrIndex].Address);\r
43ca1753 883\r
76cd3ffa
JW
884 if (UnspecifiedSrc) {\r
885 if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {\r
43ca1753 886 //\r
76cd3ffa 887 // Select the interface automatically.\r
43ca1753 888 //\r
76cd3ffa 889 CopyMem(&Private->SrcAddress, Addr, sizeof(Private->SrcAddress));\r
43ca1753
ZL
890 break;\r
891 }\r
76cd3ffa 892 } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
43ca1753 893 //\r
76cd3ffa 894 // Match a certain interface address.\r
43ca1753
ZL
895 //\r
896 break;\r
76cd3ffa
JW
897 } \r
898 }\r
899\r
900 if (AddrIndex < IfInfo->AddressInfoCount) {\r
901 //\r
902 // Found a nic handle with right interface address.\r
903 //\r
904 break;\r
43ca1753
ZL
905 }\r
906\r
907 FreePool (IfInfo);\r
908 IfInfo = NULL;\r
909 }\r
910 //\r
911 // No exact interface address matched.\r
912 //\r
913\r
914 if (HandleIndex == HandleNum) {\r
dded3ae8 915 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_CONFIGD_NIC_NF), gShellNetwork2HiiHandle);\r
43ca1753
ZL
916 Status = EFI_NOT_FOUND;\r
917 goto ON_ERROR;\r
918 }\r
919\r
920 Private->NicHandle = HandleBuffer[HandleIndex];\r
921\r
922 ASSERT (Ip6Sb != NULL);\r
923 Status = Ip6Sb->CreateChild (Ip6Sb, &Private->Ip6ChildHandle);\r
924\r
925 if (EFI_ERROR (Status)) {\r
926 goto ON_ERROR;\r
927 }\r
928\r
929 Status = gBS->OpenProtocol (\r
930 Private->Ip6ChildHandle,\r
931 &gEfiIp6ProtocolGuid,\r
932 (VOID **) &Private->Ip6,\r
933 Private->ImageHandle,\r
934 Private->Ip6ChildHandle,\r
935 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
936 );\r
937 if (EFI_ERROR (Status)) {\r
938 goto ON_ERROR;\r
939 }\r
940\r
941 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
942\r
943 //\r
944 // Configure the ip6 instance for icmp6 packet exchange.\r
945 //\r
946 Ip6Config.DefaultProtocol = 58;\r
947 Ip6Config.AcceptAnyProtocol = FALSE;\r
948 Ip6Config.AcceptIcmpErrors = TRUE;\r
949 Ip6Config.AcceptPromiscuous = FALSE;\r
950 Ip6Config.TrafficClass = 0;\r
951 Ip6Config.HopLimit = 128;\r
952 Ip6Config.FlowLabel = 0;\r
953 Ip6Config.ReceiveTimeout = 0;\r
954 Ip6Config.TransmitTimeout = 0;\r
955\r
956 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
957\r
958 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
959\r
960 Status = Private->Ip6->Configure (Private->Ip6, &Ip6Config);\r
961\r
962 if (EFI_ERROR (Status)) {\r
963 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_CONFIG), gShellNetwork2HiiHandle, Status);\r
964 goto ON_ERROR;\r
965 }\r
966\r
967 return EFI_SUCCESS;\r
968\r
969ON_ERROR:\r
970 if (HandleBuffer != NULL) {\r
971 FreePool (HandleBuffer);\r
972 }\r
973\r
974 if (IfInfo != NULL) {\r
975 FreePool (IfInfo);\r
976 }\r
977\r
978 if ((Ip6Sb != NULL) && (Private->Ip6ChildHandle != NULL)) {\r
979 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
980 }\r
981\r
982 return Status;\r
983}\r
984\r
985/**\r
986 Destroy the IP6 instance.\r
987\r
988 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
989\r
990**/\r
991VOID\r
992Ping6DestroyIpInstance (\r
993 IN PING6_PRIVATE_DATA *Private\r
994 )\r
995{\r
996 EFI_STATUS Status;\r
997 EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb;\r
998\r
999 gBS->CloseProtocol (\r
1000 Private->Ip6ChildHandle,\r
1001 &gEfiIp6ProtocolGuid,\r
1002 Private->ImageHandle,\r
1003 Private->Ip6ChildHandle\r
1004 );\r
1005\r
1006 Status = gBS->HandleProtocol (\r
1007 Private->NicHandle,\r
1008 &gEfiIp6ServiceBindingProtocolGuid,\r
1009 (VOID **) &Ip6Sb\r
1010 );\r
1011\r
1012 if (!EFI_ERROR(Status)) {\r
1013 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
1014 }\r
1015}\r
1016\r
1017/**\r
1018 The Ping6 Process.\r
1019\r
1020 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
1021 @param[in] SendNumber The send request count.\r
1022 @param[in] BufferSize The send buffer size.\r
1023 @param[in] SrcAddress The source IPv6 address.\r
1024 @param[in] DstAddress The destination IPv6 address.\r
1025\r
1026 @retval SHELL_SUCCESS The ping6 processed successfullly.\r
1027 @retval others The ping6 processed unsuccessfully.\r
1028\r
1029**/\r
1030SHELL_STATUS\r
1031ShellPing6 (\r
1032 IN EFI_HANDLE ImageHandle,\r
1033 IN UINT32 SendNumber,\r
1034 IN UINT32 BufferSize,\r
1035 IN EFI_IPv6_ADDRESS *SrcAddress,\r
1036 IN EFI_IPv6_ADDRESS *DstAddress\r
1037 )\r
1038{\r
1039 EFI_STATUS Status;\r
1040 EFI_INPUT_KEY Key;\r
1041 PING6_PRIVATE_DATA *Private;\r
1042 PING6_ICMP6_TX_INFO *TxInfo;\r
1043 LIST_ENTRY *Entry;\r
1044 LIST_ENTRY *NextEntry;\r
1045 SHELL_STATUS ShellStatus;\r
1046\r
1047 ShellStatus = SHELL_SUCCESS;\r
1048 Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA));\r
1049\r
e7a5a238
RN
1050 if (Private == NULL) {\r
1051 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"Ping6");\r
1052 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
1053 goto ON_EXIT;\r
1054 }\r
43ca1753
ZL
1055\r
1056 Private->ImageHandle = ImageHandle;\r
1057 Private->SendNum = SendNumber;\r
1058 Private->BufferSize = BufferSize;\r
1059 Private->RttMin = ~((UINT64 )(0x0));\r
1060 Private->Status = EFI_NOT_READY;\r
1061\r
1062 InitializeListHead (&Private->TxList);\r
1063\r
1064 IP6_COPY_ADDRESS (&Private->SrcAddress, SrcAddress);\r
1065 IP6_COPY_ADDRESS (&Private->DstAddress, DstAddress);\r
1066\r
1067 //\r
1068 // Open and configure a ip6 instance for ping6.\r
1069 //\r
1070 Status = Ping6CreateIpInstance (Private);\r
1071\r
1072 if (EFI_ERROR (Status)) {\r
1073 ShellStatus = SHELL_ACCESS_DENIED;\r
1074 goto ON_EXIT;\r
1075 }\r
1076 //\r
1077 // Print the command line itself.\r
1078 //\r
1079 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_START), gShellNetwork2HiiHandle, mIp6DstString, Private->BufferSize);\r
1080 //\r
1081 // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
1082 //\r
1083 Status = Ping6OnReceiveEchoReply (Private);\r
1084\r
1085 if (EFI_ERROR (Status)) {\r
1086 ShellStatus = SHELL_ACCESS_DENIED;\r
1087 goto ON_EXIT;\r
1088 }\r
1089 //\r
1090 // Create and start timer to send icmp6 echo request packet per second.\r
1091 //\r
1092 Status = gBS->CreateEvent (\r
1093 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1094 TPL_CALLBACK,\r
1095 Ping6OnTimerRoutine6,\r
1096 Private,\r
1097 &Private->Timer\r
1098 );\r
1099\r
1100 if (EFI_ERROR (Status)) {\r
1101 ShellStatus = SHELL_ACCESS_DENIED;\r
1102 goto ON_EXIT;\r
1103 }\r
825f09b7
ZL
1104\r
1105 //\r
1106 // Start a timer to calculate the RTT.\r
1107 //\r
1108 Status = Ping6InitRttTimer (Private);\r
1109 if (EFI_ERROR (Status)) {\r
1110 ShellStatus = SHELL_ACCESS_DENIED;\r
1111 goto ON_EXIT;\r
1112 }\r
1113\r
43ca1753
ZL
1114 //\r
1115 // Create a ipv6 token to send the first icmp6 echo request packet.\r
1116 //\r
1117 Status = Ping6SendEchoRequest (Private);\r
1118 //\r
1119 // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
1120 //\r
1121 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
1122 ShellStatus = SHELL_ACCESS_DENIED;\r
1123 if(Status == EFI_NOT_FOUND) {\r
1124 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN), gShellNetwork2HiiHandle, mIp6DstString);\r
1125 }\r
1126\r
1127 goto ON_EXIT;\r
1128 }\r
1129\r
1130 Status = gBS->SetTimer (\r
1131 Private->Timer,\r
1132 TimerPeriodic,\r
1133 PING6_ONE_SECOND\r
1134 );\r
1135\r
1136 if (EFI_ERROR (Status)) {\r
1137 ShellStatus = SHELL_ACCESS_DENIED;\r
1138 goto ON_EXIT;\r
1139 }\r
1140 //\r
1141 // Control the ping6 process by two factors:\r
1142 // 1. Hot key\r
1143 // 2. Private->Status\r
1144 // 2.1. success means all icmp6 echo request packets get reply packets.\r
1145 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
1146 // 2.3. noready means ping6 process is on-the-go.\r
1147 //\r
1148 while (Private->Status == EFI_NOT_READY) {\r
1149 Private->Ip6->Poll (Private->Ip6);\r
1150\r
1151 //\r
1152 // Terminate the ping6 process by 'esc' or 'ctl-c'.\r
1153 //\r
1154 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
1155\r
1156 if (!EFI_ERROR(Status)) {\r
1157 if ((Key.UnicodeChar == 0x1b) || (Key.UnicodeChar == 0x03) ||\r
1158 ((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_ESC))) {\r
1159 goto ON_STAT;\r
1160 }\r
1161 }\r
1162 }\r
1163\r
1164ON_STAT:\r
1165 //\r
1166 // Display the statistics in all.\r
1167 //\r
1168 gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
1169\r
1170 if (Private->TxCount != 0) {\r
1171 ShellPrintHiiEx (\r
1172 -1,\r
1173 -1,\r
1174 NULL,\r
1175 STRING_TOKEN (STR_PING6_STAT),\r
1176 gShellNetwork2HiiHandle,\r
1177 Private->TxCount,\r
1178 Private->RxCount,\r
1179 (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,\r
1180 Private->RttSum\r
1181 );\r
1182 }\r
1183\r
1184 if (Private->RxCount != 0) {\r
1185 ShellPrintHiiEx (\r
1186 -1,\r
1187 -1,\r
1188 NULL,\r
1189 STRING_TOKEN (STR_PING6_RTT),\r
1190 gShellNetwork2HiiHandle,\r
1191 Private->RttMin,\r
825f09b7 1192 Private->RttMin + Private->TimerPeriod,\r
43ca1753 1193 Private->RttMax,\r
825f09b7
ZL
1194 Private->RttMax + Private->TimerPeriod,\r
1195 DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL),\r
1196 DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + Private->TimerPeriod\r
43ca1753
ZL
1197 );\r
1198 }\r
1199\r
1200ON_EXIT:\r
1201\r
1202 if (Private != NULL) {\r
1203 Private->Status = EFI_ABORTED;\r
1204\r
1205 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
1206 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
1207\r
1208 Status = Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
1209\r
1210 RemoveEntryList (&TxInfo->Link);\r
1211 Ping6DestroyTxInfo (TxInfo);\r
1212 }\r
1213\r
825f09b7
ZL
1214 Ping6FreeRttTimer (Private);\r
1215\r
43ca1753
ZL
1216 if (Private->Timer != NULL) {\r
1217 gBS->CloseEvent (Private->Timer);\r
1218 }\r
1219\r
1220 if (Private->Ip6 != NULL) {\r
1221 Status = Private->Ip6->Cancel (Private->Ip6, &Private->RxToken);\r
1222 }\r
1223\r
1224 if (Private->RxToken.Event != NULL) {\r
1225 gBS->CloseEvent (Private->RxToken.Event);\r
1226 }\r
1227\r
1228 if (Private->Ip6ChildHandle != NULL) {\r
1229 Ping6DestroyIpInstance (Private);\r
1230 }\r
1231\r
1232 FreePool (Private);\r
1233 }\r
1234\r
1235 return ShellStatus;\r
1236}\r
1237\r
1238/**\r
1239 Function for 'ping6' command.\r
1240\r
1241 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
1242 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
1243\r
1244 @retval SHELL_SUCCESS The ping6 processed successfullly.\r
1245 @retval others The ping6 processed unsuccessfully.\r
1246\r
1247**/\r
1248SHELL_STATUS\r
1249EFIAPI\r
1250ShellCommandRunPing6 (\r
1251 IN EFI_HANDLE ImageHandle,\r
1252 IN EFI_SYSTEM_TABLE *SystemTable\r
1253 )\r
1254{\r
1255 EFI_STATUS Status;\r
1256 SHELL_STATUS ShellStatus;\r
1257 EFI_IPv6_ADDRESS DstAddress;\r
1258 EFI_IPv6_ADDRESS SrcAddress;\r
1259 UINT64 BufferSize;\r
1260 UINTN SendNumber;\r
1261 LIST_ENTRY *ParamPackage;\r
1262 CONST CHAR16 *ValueStr;\r
1263 CONST CHAR16 *ValueStrPtr;\r
1264 UINTN NonOptionCount;\r
1265 CHAR16 *ProblemParam;\r
1266\r
1267 ProblemParam = NULL;\r
1268 ShellStatus = SHELL_SUCCESS;\r
1269\r
1270 Status = ShellCommandLineParseEx (Ping6ParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);\r
1271 if (EFI_ERROR(Status)) {\r
1272 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle);\r
1273 ShellStatus = SHELL_INVALID_PARAMETER;\r
1274 goto ON_EXIT;\r
1275 }\r
1276\r
1277 SendNumber = 10;\r
1278 BufferSize = 16;\r
1279\r
1280 //\r
268d3445 1281 // Parse the parameter of count number.\r
43ca1753
ZL
1282 //\r
1283 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
1284 ValueStrPtr = ValueStr;\r
1285 if (ValueStr != NULL) {\r
1286 SendNumber = ShellStrToUintn (ValueStrPtr);\r
1287\r
1288 //\r
1289 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1290 //\r
1291 if ((SendNumber == 0) || (SendNumber > PING6_MAX_SEND_NUMBER)) {\r
1292 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER), gShellNetwork2HiiHandle, ValueStr);\r
1293 ShellStatus = SHELL_INVALID_PARAMETER;\r
1294 goto ON_EXIT;\r
1295 }\r
1296 }\r
1297 //\r
268d3445 1298 // Parse the parameter of buffer size.\r
43ca1753
ZL
1299 //\r
1300 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
1301 ValueStrPtr = ValueStr;\r
1302 if (ValueStr != NULL) {\r
1303 BufferSize = ShellStrToUintn (ValueStrPtr);\r
1304\r
1305 //\r
1306 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1307 //\r
1308 if ((BufferSize < 16) || (BufferSize > PING6_MAX_BUFFER_SIZE)) {\r
1309 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE), gShellNetwork2HiiHandle, ValueStr);\r
1310 ShellStatus = SHELL_INVALID_PARAMETER;\r
1311 goto ON_EXIT;\r
1312 }\r
1313 }\r
1314\r
1315 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
1316 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
1317\r
1318 //\r
268d3445 1319 // Parse the parameter of source ip address.\r
43ca1753
ZL
1320 //\r
1321 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
1322 ValueStrPtr = ValueStr;\r
1323 if (ValueStr != NULL) {\r
1324 mIp6SrcString = ValueStr;\r
1325 Status = NetLibStrToIp6 (ValueStrPtr, &SrcAddress);\r
1326 if (EFI_ERROR (Status)) {\r
1327 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr);\r
1328 ShellStatus = SHELL_INVALID_PARAMETER;\r
1329 goto ON_EXIT;\r
1330 }\r
1331 }\r
1332 //\r
268d3445 1333 // Parse the parameter of destination ip address.\r
43ca1753
ZL
1334 //\r
1335 NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
1336 ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1));\r
1337 if (NonOptionCount != 2) {\r
1338 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle);\r
1339 ShellStatus = SHELL_INVALID_PARAMETER;\r
1340 goto ON_EXIT;\r
1341 }\r
1342 ValueStrPtr = ValueStr;\r
1343 if (ValueStr != NULL) {\r
1344 mIp6DstString = ValueStr;\r
1345 Status = NetLibStrToIp6 (ValueStrPtr, &DstAddress);\r
1346 if (EFI_ERROR (Status)) {\r
1347 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr);\r
1348 ShellStatus = SHELL_INVALID_PARAMETER;\r
1349 goto ON_EXIT;\r
1350 }\r
1351 }\r
43ca1753 1352\r
43ca1753
ZL
1353 //\r
1354 // Enter into ping6 process.\r
1355 //\r
1356 ShellStatus = ShellPing6 (\r
1357 ImageHandle,\r
1358 (UINT32)SendNumber,\r
1359 (UINT32)BufferSize,\r
1360 &SrcAddress,\r
1361 &DstAddress\r
1362 );\r
1363\r
1364ON_EXIT:\r
1365 ShellCommandLineFreeVarList (ParamPackage);\r
1366 return ShellStatus;\r
1367}\r
1368\r