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