]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
ShellPkg: Fix Ping GetTimerPeriod API failure
[mirror_edk2.git] / ShellPkg / Library / UefiShellNetwork1CommandsLib / Ping.c
... / ...
CommitLineData
1/** @file\r
2 The implementation for Ping shell command.\r
3\r
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
7\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12#include "UefiShellNetwork1CommandsLib.h"\r
13\r
14#define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))\r
15\r
16UINT64 mCurrentTick = 0;\r
17\r
18//\r
19// Function templates to match the IPv4 and IPv6 commands that we use.\r
20//\r
21typedef\r
22EFI_STATUS\r
23(EFIAPI *PING_IPX_POLL)(\r
24 IN VOID *This\r
25 );\r
26\r
27typedef\r
28EFI_STATUS\r
29(EFIAPI *PING_IPX_TRANSMIT)(\r
30 IN VOID *This,\r
31 IN VOID *Token\r
32 );\r
33\r
34typedef\r
35EFI_STATUS\r
36(EFIAPI *PING_IPX_RECEIVE)(\r
37 IN VOID *This,\r
38 IN VOID *Token\r
39 );\r
40\r
41typedef\r
42EFI_STATUS\r
43(EFIAPI *PING_IPX_CANCEL)(\r
44 IN VOID *This,\r
45 IN VOID *Token OPTIONAL\r
46 );\r
47\r
48///\r
49/// A set of pointers to either IPv6 or IPv4 functions.\r
50/// Unknown which one to the ping command.\r
51///\r
52typedef struct {\r
53 PING_IPX_TRANSMIT Transmit;\r
54 PING_IPX_RECEIVE Receive;\r
55 PING_IPX_CANCEL Cancel;\r
56 PING_IPX_POLL Poll;\r
57} PING_IPX_PROTOCOL;\r
58\r
59typedef union {\r
60 VOID *RxData;\r
61 VOID *TxData;\r
62} PING_PACKET;\r
63\r
64//\r
65// PING_IPX_COMPLETION_TOKEN\r
66// structures are used for both transmit and receive operations.\r
67// This version is IP-unaware.\r
68//\r
69typedef struct {\r
70 EFI_EVENT Event;\r
71 EFI_STATUS Status;\r
72 PING_PACKET Packet;\r
73} PING_IPX_COMPLETION_TOKEN;\r
74\r
75#pragma pack(1)\r
76typedef struct _ICMPX_ECHO_REQUEST_REPLY {\r
77 UINT8 Type;\r
78 UINT8 Code;\r
79 UINT16 Checksum;\r
80 UINT16 Identifier;\r
81 UINT16 SequenceNum;\r
82 UINT32 TimeStamp;\r
83 UINT8 Data[1];\r
84} ICMPX_ECHO_REQUEST_REPLY;\r
85#pragma pack()\r
86\r
87typedef struct _PING_ICMP_TX_INFO {\r
88 LIST_ENTRY Link;\r
89 UINT16 SequenceNum;\r
90 UINT32 TimeStamp;\r
91 PING_IPX_COMPLETION_TOKEN *Token;\r
92} PING_ICMPX_TX_INFO;\r
93\r
94#define DEFAULT_TIMEOUT 5000\r
95#define MAX_SEND_NUMBER 10000\r
96#define MAX_BUFFER_SIZE 32768\r
97#define DEFAULT_TIMER_PERIOD 358049\r
98#define ONE_SECOND 10000000\r
99#define PING_IP_CHOICE_IP4 1\r
100#define PING_IP_CHOICE_IP6 2\r
101#define DEFAULT_SEND_COUNT 10\r
102#define DEFAULT_BUFFER_SIZE 16\r
103#define ICMP_V4_ECHO_REQUEST 0x8\r
104#define ICMP_V4_ECHO_REPLY 0x0\r
105#define STALL_1_MILLI_SECOND 1000\r
106\r
107#define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')\r
108typedef struct _PING_PRIVATE_DATA {\r
109 UINT32 Signature;\r
110 EFI_HANDLE NicHandle;\r
111 EFI_HANDLE IpChildHandle;\r
112 EFI_EVENT Timer;\r
113\r
114 UINT32 TimerPeriod;\r
115 UINT32 RttTimerTick;\r
116 EFI_EVENT RttTimer;\r
117\r
118 EFI_STATUS Status;\r
119 LIST_ENTRY TxList;\r
120 UINT16 RxCount;\r
121 UINT16 TxCount;\r
122 UINT64 RttSum;\r
123 UINT64 RttMin;\r
124 UINT64 RttMax;\r
125 UINT32 SequenceNum;\r
126\r
127 UINT32 SendNum;\r
128 UINT32 BufferSize;\r
129 UINT32 IpChoice;\r
130\r
131 PING_IPX_PROTOCOL ProtocolPointers;\r
132 VOID *IpProtocol;\r
133 UINT8 SrcAddress[MAX (sizeof (EFI_IPv6_ADDRESS), sizeof (EFI_IPv4_ADDRESS))];\r
134 UINT8 DstAddress[MAX (sizeof (EFI_IPv6_ADDRESS), sizeof (EFI_IPv4_ADDRESS))];\r
135 PING_IPX_COMPLETION_TOKEN RxToken;\r
136 UINT16 FailedCount;\r
137} PING_PRIVATE_DATA;\r
138\r
139/**\r
140 Calculate the internet checksum (see RFC 1071).\r
141\r
142 @param[in] Packet Buffer which contains the data to be checksummed.\r
143 @param[in] Length Length to be checksummed.\r
144\r
145 @retval Checksum Returns the 16 bit ones complement of\r
146 ones complement sum of 16 bit words\r
147**/\r
148UINT16\r
149NetChecksum (\r
150 IN UINT8 *Buffer,\r
151 IN UINT32 Length\r
152 )\r
153{\r
154 UINT32 Sum;\r
155 UINT8 Odd;\r
156 UINT16 *Packet;\r
157\r
158 Packet = (UINT16 *)Buffer;\r
159\r
160 Sum = 0;\r
161 Odd = (UINT8)(Length & 1);\r
162 Length >>= 1;\r
163 while ((Length--) != 0) {\r
164 Sum += *Packet++;\r
165 }\r
166\r
167 if (Odd != 0) {\r
168 Sum += *(UINT8 *)Packet;\r
169 }\r
170\r
171 Sum = (Sum & 0xffff) + (Sum >> 16);\r
172\r
173 //\r
174 // in case above carried\r
175 //\r
176 Sum += Sum >> 16;\r
177\r
178 return (UINT16)Sum;\r
179}\r
180\r
181/**\r
182 Reads and returns the current value of register.\r
183 In IA64, the register is the Interval Timer Vector (ITV).\r
184 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)\r
185\r
186 @return The current value of the register.\r
187\r
188**/\r
189\r
190STATIC CONST SHELL_PARAM_ITEM PingParamList[] = {\r
191 {\r
192 L"-l",\r
193 TypeValue\r
194 },\r
195 {\r
196 L"-n",\r
197 TypeValue\r
198 },\r
199 {\r
200 L"-s",\r
201 TypeValue\r
202 },\r
203 {\r
204 L"-_s",\r
205 TypeValue\r
206 },\r
207 {\r
208 L"-_ip6",\r
209 TypeFlag\r
210 },\r
211 {\r
212 NULL,\r
213 TypeMax\r
214 },\r
215};\r
216\r
217//\r
218// Global Variables in Ping command.\r
219//\r
220STATIC CONST CHAR16 *mDstString;\r
221STATIC CONST CHAR16 *mSrcString;\r
222\r
223/**\r
224 RTT timer tick routine.\r
225\r
226 @param[in] Event A EFI_EVENT type event.\r
227 @param[in] Context The pointer to Context.\r
228\r
229**/\r
230VOID\r
231EFIAPI\r
232RttTimerTickRoutine (\r
233 IN EFI_EVENT Event,\r
234 IN VOID *Context\r
235 )\r
236{\r
237 UINT32 *RttTimerTick;\r
238\r
239 RttTimerTick = (UINT32 *)Context;\r
240 (*RttTimerTick)++;\r
241}\r
242\r
243/**\r
244 Get the timer period of the system.\r
245\r
246 This function tries to get the system timer period by creating\r
247 an 1ms period timer.\r
248\r
249 @return System timer period in MS, or 0 if operation failed.\r
250\r
251**/\r
252UINT32\r
253GetTimerPeriod (\r
254 VOID\r
255 )\r
256{\r
257 EFI_STATUS Status;\r
258 UINT32 RttTimerTick;\r
259 EFI_EVENT TimerEvent;\r
260 UINT32 StallCounter;\r
261 EFI_TPL OldTpl;\r
262 UINT32 TimerPeriod;\r
263\r
264 RttTimerTick = 0;\r
265 StallCounter = 0;\r
266 TimerPeriod = 0;\r
267\r
268 Status = gBS->CreateEvent (\r
269 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
270 TPL_NOTIFY,\r
271 RttTimerTickRoutine,\r
272 &RttTimerTick,\r
273 &TimerEvent\r
274 );\r
275 if (EFI_ERROR (Status)) {\r
276 return 0;\r
277 }\r
278\r
279 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
280 Status = gBS->SetTimer (\r
281 TimerEvent,\r
282 TimerPeriodic,\r
283 TICKS_PER_MS\r
284 );\r
285 if (EFI_ERROR (Status)) {\r
286 gBS->CloseEvent (TimerEvent);\r
287 return 0;\r
288 }\r
289\r
290 while (RttTimerTick < 10) {\r
291 gBS->Stall (STALL_1_MILLI_SECOND);\r
292 ++StallCounter;\r
293 }\r
294\r
295 gBS->RestoreTPL (OldTpl);\r
296\r
297 gBS->SetTimer (TimerEvent, TimerCancel, 0);\r
298 gBS->CloseEvent (TimerEvent);\r
299\r
300 TimerPeriod = StallCounter / RttTimerTick;\r
301 if (TimerPeriod != 0) {\r
302 return TimerPeriod;\r
303 } else {\r
304 return 1;\r
305 }\r
306}\r
307\r
308/**\r
309 Initialize the timer event for RTT (round trip time).\r
310\r
311 @param[in] Private The pointer to PING_PRIVATE_DATA.\r
312\r
313 @retval EFI_SUCCESS RTT timer is started.\r
314 @retval Others Failed to start the RTT timer.\r
315\r
316**/\r
317EFI_STATUS\r
318PingInitRttTimer (\r
319 PING_PRIVATE_DATA *Private\r
320 )\r
321{\r
322 EFI_STATUS Status;\r
323\r
324 Private->TimerPeriod = GetTimerPeriod ();\r
325 if (Private->TimerPeriod == 0) {\r
326 return EFI_ABORTED;\r
327 }\r
328\r
329 Private->RttTimerTick = 0;\r
330 Status = gBS->CreateEvent (\r
331 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
332 TPL_NOTIFY,\r
333 RttTimerTickRoutine,\r
334 &Private->RttTimerTick,\r
335 &Private->RttTimer\r
336 );\r
337 if (EFI_ERROR (Status)) {\r
338 return Status;\r
339 }\r
340\r
341 Status = gBS->SetTimer (\r
342 Private->RttTimer,\r
343 TimerPeriodic,\r
344 TICKS_PER_MS\r
345 );\r
346 if (EFI_ERROR (Status)) {\r
347 gBS->CloseEvent (Private->RttTimer);\r
348 return Status;\r
349 }\r
350\r
351 return EFI_SUCCESS;\r
352}\r
353\r
354/**\r
355 Free RTT timer event resource.\r
356\r
357 @param[in] Private The pointer to PING_PRIVATE_DATA.\r
358\r
359**/\r
360VOID\r
361PingFreeRttTimer (\r
362 PING_PRIVATE_DATA *Private\r
363 )\r
364{\r
365 if (Private->RttTimer != NULL) {\r
366 gBS->SetTimer (Private->RttTimer, TimerCancel, 0);\r
367 gBS->CloseEvent (Private->RttTimer);\r
368 }\r
369}\r
370\r
371/**\r
372 Read the current time.\r
373\r
374 @param[in] Private The pointer to PING_PRIVATE_DATA.\r
375\r
376 @retval the current tick value.\r
377**/\r
378UINT32\r
379ReadTime (\r
380 PING_PRIVATE_DATA *Private\r
381 )\r
382{\r
383 return Private->RttTimerTick;\r
384}\r
385\r
386/**\r
387 Calculate a duration in ms.\r
388\r
389 @param[in] Private The pointer to PING_PRIVATE_DATA.\r
390 @param[in] Begin The start point of time.\r
391 @param[in] End The end point of time.\r
392\r
393 @return The duration in ms.\r
394 @retval 0 The parameters were not valid.\r
395**/\r
396UINT32\r
397CalculateTick (\r
398 PING_PRIVATE_DATA *Private,\r
399 IN UINT32 Begin,\r
400 IN UINT32 End\r
401 )\r
402{\r
403 if (End < Begin) {\r
404 return (0);\r
405 }\r
406\r
407 return (End - Begin) * Private->TimerPeriod;\r
408}\r
409\r
410/**\r
411 Destroy PING_ICMPX_TX_INFO, and recollect the memory.\r
412\r
413 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.\r
414 @param[in] IpChoice Whether the token is IPv4 or IPv6\r
415**/\r
416VOID\r
417PingDestroyTxInfo (\r
418 IN PING_ICMPX_TX_INFO *TxInfo,\r
419 IN UINT32 IpChoice\r
420 )\r
421{\r
422 EFI_IP6_TRANSMIT_DATA *Ip6TxData;\r
423 EFI_IP4_TRANSMIT_DATA *Ip4TxData;\r
424 EFI_IP6_FRAGMENT_DATA *FragData;\r
425 UINTN Index;\r
426\r
427 if (TxInfo == NULL) {\r
428 return;\r
429 }\r
430\r
431 if (TxInfo->Token != NULL) {\r
432 if (TxInfo->Token->Event != NULL) {\r
433 gBS->CloseEvent (TxInfo->Token->Event);\r
434 }\r
435\r
436 if (TxInfo->Token->Packet.TxData != NULL) {\r
437 if (IpChoice == PING_IP_CHOICE_IP6) {\r
438 Ip6TxData = TxInfo->Token->Packet.TxData;\r
439\r
440 if (Ip6TxData->OverrideData != NULL) {\r
441 FreePool (Ip6TxData->OverrideData);\r
442 }\r
443\r
444 if (Ip6TxData->ExtHdrs != NULL) {\r
445 FreePool (Ip6TxData->ExtHdrs);\r
446 }\r
447\r
448 for (Index = 0; Index < Ip6TxData->FragmentCount; Index++) {\r
449 FragData = Ip6TxData->FragmentTable[Index].FragmentBuffer;\r
450 if (FragData != NULL) {\r
451 FreePool (FragData);\r
452 }\r
453 }\r
454 } else {\r
455 Ip4TxData = TxInfo->Token->Packet.TxData;\r
456\r
457 if (Ip4TxData->OverrideData != NULL) {\r
458 FreePool (Ip4TxData->OverrideData);\r
459 }\r
460\r
461 for (Index = 0; Index < Ip4TxData->FragmentCount; Index++) {\r
462 FragData = Ip4TxData->FragmentTable[Index].FragmentBuffer;\r
463 if (FragData != NULL) {\r
464 FreePool (FragData);\r
465 }\r
466 }\r
467 }\r
468 }\r
469\r
470 FreePool (TxInfo->Token);\r
471 }\r
472\r
473 FreePool (TxInfo);\r
474}\r
475\r
476/**\r
477 Match the request, and reply with SequenceNum/TimeStamp.\r
478\r
479 @param[in] Private The pointer to PING_PRIVATE_DATA.\r
480 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.\r
481\r
482 @retval EFI_SUCCESS The match is successful.\r
483 @retval EFI_NOT_FOUND The reply can't be matched with any request.\r
484\r
485**/\r
486EFI_STATUS\r
487Ping6MatchEchoReply (\r
488 IN PING_PRIVATE_DATA *Private,\r
489 IN ICMPX_ECHO_REQUEST_REPLY *Packet\r
490 )\r
491{\r
492 PING_ICMPX_TX_INFO *TxInfo;\r
493 LIST_ENTRY *Entry;\r
494 LIST_ENTRY *NextEntry;\r
495\r
496 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
497 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
498\r
499 if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) {\r
500 Private->RxCount++;\r
501 RemoveEntryList (&TxInfo->Link);\r
502 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
503 return EFI_SUCCESS;\r
504 }\r
505 }\r
506\r
507 return EFI_NOT_FOUND;\r
508}\r
509\r
510/**\r
511 The original intention is to send a request.\r
512 Currently, the application retransmits an icmp6 echo request packet\r
513 per second in sendnumber times that is specified by the user.\r
514 Because nothing can be done here, all things move to the timer rountine.\r
515\r
516 @param[in] Event A EFI_EVENT type event.\r
517 @param[in] Context The pointer to Context.\r
518\r
519**/\r
520VOID\r
521EFIAPI\r
522Ping6OnEchoRequestSent (\r
523 IN EFI_EVENT Event,\r
524 IN VOID *Context\r
525 )\r
526{\r
527}\r
528\r
529/**\r
530 receive reply, match and print reply infomation.\r
531\r
532 @param[in] Event A EFI_EVENT type event.\r
533 @param[in] Context The pointer to context.\r
534\r
535**/\r
536VOID\r
537EFIAPI\r
538Ping6OnEchoReplyReceived (\r
539 IN EFI_EVENT Event,\r
540 IN VOID *Context\r
541 )\r
542{\r
543 EFI_STATUS Status;\r
544 PING_PRIVATE_DATA *Private;\r
545 ICMPX_ECHO_REQUEST_REPLY *Reply;\r
546 UINT32 PayLoad;\r
547 UINT32 Rtt;\r
548\r
549 Private = (PING_PRIVATE_DATA *)Context;\r
550\r
551 if ((Private == NULL) || (Private->Status == EFI_ABORTED) || (Private->Signature != PING_PRIVATE_DATA_SIGNATURE)) {\r
552 return;\r
553 }\r
554\r
555 if (Private->RxToken.Packet.RxData == NULL) {\r
556 return;\r
557 }\r
558\r
559 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
560 Reply = ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer;\r
561 PayLoad = ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->DataLength;\r
562 if (((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->NextHeader != IP6_ICMP) {\r
563 goto ON_EXIT;\r
564 }\r
565\r
566 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS *)&Private->DstAddress) &&\r
567 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv6_ADDRESS *)&Private->DstAddress))\r
568 {\r
569 goto ON_EXIT;\r
570 }\r
571\r
572 if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) {\r
573 goto ON_EXIT;\r
574 }\r
575 } else {\r
576 Reply = ((EFI_IP4_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer;\r
577 PayLoad = ((EFI_IP4_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->DataLength;\r
578 if (!IP4_IS_MULTICAST (EFI_IP4 (*(EFI_IPv4_ADDRESS *)Private->DstAddress)) &&\r
579 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv4_ADDRESS *)&Private->DstAddress))\r
580 {\r
581 goto ON_EXIT;\r
582 }\r
583\r
584 if ((Reply->Type != ICMP_V4_ECHO_REPLY) || (Reply->Code != 0)) {\r
585 goto ON_EXIT;\r
586 }\r
587 }\r
588\r
589 if (PayLoad != Private->BufferSize) {\r
590 goto ON_EXIT;\r
591 }\r
592\r
593 //\r
594 // Check whether the reply matches the sent request before.\r
595 //\r
596 Status = Ping6MatchEchoReply (Private, Reply);\r
597 if (EFI_ERROR (Status)) {\r
598 goto ON_EXIT;\r
599 }\r
600\r
601 //\r
602 // Display statistics on this icmp6 echo reply packet.\r
603 //\r
604 Rtt = CalculateTick (Private, Reply->TimeStamp, ReadTime (Private));\r
605\r
606 Private->RttSum += Rtt;\r
607 Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
608 Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax;\r
609\r
610 ShellPrintHiiEx (\r
611 -1,\r
612 -1,\r
613 NULL,\r
614 STRING_TOKEN (STR_PING_REPLY_INFO),\r
615 gShellNetwork1HiiHandle,\r
616 PayLoad,\r
617 mDstString,\r
618 Reply->SequenceNum,\r
619 Private->IpChoice == PING_IP_CHOICE_IP6 ? ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->HopLimit : 0,\r
620 Rtt,\r
621 Rtt + Private->TimerPeriod\r
622 );\r
623\r
624ON_EXIT:\r
625\r
626 //\r
627 // Recycle the packet before reusing RxToken\r
628 //\r
629 gBS->SignalEvent (Private->IpChoice == PING_IP_CHOICE_IP6 ? ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->RecycleSignal : ((EFI_IP4_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->RecycleSignal);\r
630\r
631 if (Private->RxCount < Private->SendNum) {\r
632 //\r
633 // Continue to receive icmp echo reply packets.\r
634 //\r
635 Private->RxToken.Status = EFI_ABORTED;\r
636\r
637 Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);\r
638\r
639 if (EFI_ERROR (Status)) {\r
640 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);\r
641 Private->Status = EFI_ABORTED;\r
642 }\r
643 } else {\r
644 //\r
645 // All reply have already been received from the dest host.\r
646 //\r
647 Private->Status = EFI_SUCCESS;\r
648 }\r
649}\r
650\r
651/**\r
652 Create a PING_IPX_COMPLETION_TOKEN.\r
653\r
654 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
655 @param[in] TimeStamp The TimeStamp of request.\r
656 @param[in] SequenceNum The SequenceNum of request.\r
657\r
658 @return The pointer of PING_IPX_COMPLETION_TOKEN.\r
659\r
660**/\r
661PING_IPX_COMPLETION_TOKEN *\r
662PingGenerateToken (\r
663 IN PING_PRIVATE_DATA *Private,\r
664 IN UINT32 TimeStamp,\r
665 IN UINT16 SequenceNum\r
666 )\r
667{\r
668 EFI_STATUS Status;\r
669 PING_IPX_COMPLETION_TOKEN *Token;\r
670 VOID *TxData;\r
671 ICMPX_ECHO_REQUEST_REPLY *Request;\r
672 UINT16 HeadSum;\r
673 UINT16 TempChecksum;\r
674\r
675 Request = AllocateZeroPool (Private->BufferSize);\r
676 if (Request == NULL) {\r
677 return NULL;\r
678 }\r
679\r
680 TxData = AllocateZeroPool (Private->IpChoice == PING_IP_CHOICE_IP6 ? sizeof (EFI_IP6_TRANSMIT_DATA) : sizeof (EFI_IP4_TRANSMIT_DATA));\r
681 if (TxData == NULL) {\r
682 FreePool (Request);\r
683 return NULL;\r
684 }\r
685\r
686 Token = AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN));\r
687 if (Token == NULL) {\r
688 FreePool (Request);\r
689 FreePool (TxData);\r
690 return NULL;\r
691 }\r
692\r
693 //\r
694 // Assembly echo request packet.\r
695 //\r
696 Request->Type = (UINT8)(Private->IpChoice == PING_IP_CHOICE_IP6 ? ICMP_V6_ECHO_REQUEST : ICMP_V4_ECHO_REQUEST);\r
697 Request->Code = 0;\r
698 Request->SequenceNum = SequenceNum;\r
699 Request->Identifier = 0;\r
700 Request->Checksum = 0;\r
701\r
702 //\r
703 // Assembly token for transmit.\r
704 //\r
705 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
706 Request->TimeStamp = TimeStamp;\r
707 ((EFI_IP6_TRANSMIT_DATA *)TxData)->ExtHdrsLength = 0;\r
708 ((EFI_IP6_TRANSMIT_DATA *)TxData)->ExtHdrs = NULL;\r
709 ((EFI_IP6_TRANSMIT_DATA *)TxData)->OverrideData = 0;\r
710 ((EFI_IP6_TRANSMIT_DATA *)TxData)->DataLength = Private->BufferSize;\r
711 ((EFI_IP6_TRANSMIT_DATA *)TxData)->FragmentCount = 1;\r
712 ((EFI_IP6_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentBuffer = (VOID *)Request;\r
713 ((EFI_IP6_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;\r
714 } else {\r
715 ((EFI_IP4_TRANSMIT_DATA *)TxData)->OptionsLength = 0;\r
716 ((EFI_IP4_TRANSMIT_DATA *)TxData)->OptionsBuffer = NULL;\r
717 ((EFI_IP4_TRANSMIT_DATA *)TxData)->OverrideData = 0;\r
718 ((EFI_IP4_TRANSMIT_DATA *)TxData)->TotalDataLength = Private->BufferSize;\r
719 ((EFI_IP4_TRANSMIT_DATA *)TxData)->FragmentCount = 1;\r
720 ((EFI_IP4_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentBuffer = (VOID *)Request;\r
721 ((EFI_IP4_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;\r
722 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[0] = Private->DstAddress[0];\r
723 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[1] = Private->DstAddress[1];\r
724 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[2] = Private->DstAddress[2];\r
725 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[3] = Private->DstAddress[3];\r
726\r
727 HeadSum = NetChecksum ((UINT8 *)Request, Private->BufferSize);\r
728 Request->TimeStamp = TimeStamp;\r
729 TempChecksum = NetChecksum ((UINT8 *)&Request->TimeStamp, sizeof (UINT64));\r
730 Request->Checksum = (UINT16)(~NetAddChecksum (HeadSum, TempChecksum));\r
731 }\r
732\r
733 Token->Status = EFI_ABORTED;\r
734 Token->Packet.TxData = TxData;\r
735\r
736 Status = gBS->CreateEvent (\r
737 EVT_NOTIFY_SIGNAL,\r
738 TPL_CALLBACK,\r
739 Ping6OnEchoRequestSent,\r
740 Private,\r
741 &Token->Event\r
742 );\r
743\r
744 if (EFI_ERROR (Status)) {\r
745 FreePool (Request);\r
746 FreePool (TxData);\r
747 FreePool (Token);\r
748 return NULL;\r
749 }\r
750\r
751 return Token;\r
752}\r
753\r
754/**\r
755 Transmit the PING_IPX_COMPLETION_TOKEN.\r
756\r
757 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
758\r
759 @retval EFI_SUCCESS Transmitted successfully.\r
760 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
761 @retval others Transmitted unsuccessfully.\r
762\r
763**/\r
764EFI_STATUS\r
765PingSendEchoRequest (\r
766 IN PING_PRIVATE_DATA *Private\r
767 )\r
768{\r
769 EFI_STATUS Status;\r
770 PING_ICMPX_TX_INFO *TxInfo;\r
771\r
772 TxInfo = AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO));\r
773\r
774 if (TxInfo == NULL) {\r
775 return EFI_OUT_OF_RESOURCES;\r
776 }\r
777\r
778 TxInfo->TimeStamp = ReadTime (Private);\r
779 TxInfo->SequenceNum = (UINT16)(Private->TxCount + 1);\r
780 TxInfo->Token = PingGenerateToken (\r
781 Private,\r
782 TxInfo->TimeStamp,\r
783 TxInfo->SequenceNum\r
784 );\r
785\r
786 if (TxInfo->Token == NULL) {\r
787 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
788 return EFI_OUT_OF_RESOURCES;\r
789 }\r
790\r
791 ASSERT (Private->ProtocolPointers.Transmit != NULL);\r
792\r
793 InsertTailList (&Private->TxList, &TxInfo->Link);\r
794\r
795 Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);\r
796\r
797 if (EFI_ERROR (Status)) {\r
798 RemoveEntryList (&TxInfo->Link);\r
799 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
800 return Status;\r
801 }\r
802\r
803 Private->TxCount++;\r
804\r
805 return EFI_SUCCESS;\r
806}\r
807\r
808/**\r
809 Place a completion token into the receive packet queue to receive the echo reply.\r
810\r
811 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
812\r
813 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
814 @retval others Put the token into the receive packet queue unsuccessfully.\r
815\r
816**/\r
817EFI_STATUS\r
818Ping6ReceiveEchoReply (\r
819 IN PING_PRIVATE_DATA *Private\r
820 )\r
821{\r
822 EFI_STATUS Status;\r
823\r
824 ZeroMem (&Private->RxToken, sizeof (PING_IPX_COMPLETION_TOKEN));\r
825\r
826 Status = gBS->CreateEvent (\r
827 EVT_NOTIFY_SIGNAL,\r
828 TPL_CALLBACK,\r
829 Ping6OnEchoReplyReceived,\r
830 Private,\r
831 &Private->RxToken.Event\r
832 );\r
833\r
834 if (EFI_ERROR (Status)) {\r
835 return Status;\r
836 }\r
837\r
838 Private->RxToken.Status = EFI_NOT_READY;\r
839\r
840 Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);\r
841 if (EFI_ERROR (Status)) {\r
842 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);\r
843 }\r
844\r
845 return Status;\r
846}\r
847\r
848/**\r
849 Remove the timeout request from the list.\r
850\r
851 @param[in] Event A EFI_EVENT type event.\r
852 @param[in] Context The pointer to Context.\r
853\r
854**/\r
855VOID\r
856EFIAPI\r
857Ping6OnTimerRoutine (\r
858 IN EFI_EVENT Event,\r
859 IN VOID *Context\r
860 )\r
861{\r
862 EFI_STATUS Status;\r
863 PING_PRIVATE_DATA *Private;\r
864 PING_ICMPX_TX_INFO *TxInfo;\r
865 LIST_ENTRY *Entry;\r
866 LIST_ENTRY *NextEntry;\r
867 UINT64 Time;\r
868\r
869 Private = (PING_PRIVATE_DATA *)Context;\r
870 if (Private->Signature != PING_PRIVATE_DATA_SIGNATURE) {\r
871 Private->Status = EFI_NOT_FOUND;\r
872 return;\r
873 }\r
874\r
875 //\r
876 // Retransmit icmp6 echo request packets per second in sendnumber times.\r
877 //\r
878 if (Private->TxCount < Private->SendNum) {\r
879 Status = PingSendEchoRequest (Private);\r
880 if (Private->TxCount != 0) {\r
881 if (EFI_ERROR (Status)) {\r
882 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_SEND_REQUEST), gShellNetwork1HiiHandle, Private->TxCount + 1);\r
883 }\r
884 }\r
885 }\r
886\r
887 //\r
888 // Check whether any icmp6 echo request in the list timeout.\r
889 //\r
890 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
891 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
892 Time = CalculateTick (Private, TxInfo->TimeStamp, ReadTime (Private));\r
893\r
894 //\r
895 // Remove the timeout echo request from txlist.\r
896 //\r
897 if (Time > DEFAULT_TIMEOUT) {\r
898 if (EFI_ERROR (TxInfo->Token->Status)) {\r
899 Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
900 }\r
901\r
902 //\r
903 // Remove the timeout icmp6 echo request from list.\r
904 //\r
905 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_TIMEOUT), gShellNetwork1HiiHandle, TxInfo->SequenceNum);\r
906\r
907 RemoveEntryList (&TxInfo->Link);\r
908 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
909\r
910 Private->RxCount++;\r
911 Private->FailedCount++;\r
912\r
913 if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
914 //\r
915 // All the left icmp6 echo request in the list timeout.\r
916 //\r
917 Private->Status = EFI_TIMEOUT;\r
918 }\r
919 }\r
920 }\r
921}\r
922\r
923/**\r
924 Determine if a IP4 address is Link Local.\r
925\r
926 169.254.1.0 through 169.254.254.255 is link local.\r
927\r
928 @param[in] Address The address to test.\r
929\r
930 @retval TRUE It is.\r
931 @retval FALSE It is not.\r
932**/\r
933BOOLEAN\r
934PingNetIp4IsLinkLocalAddr (\r
935 IN CONST EFI_IPv4_ADDRESS *Address\r
936 )\r
937{\r
938 return ((BOOLEAN)(Address->Addr[0] == 169 && Address->Addr[1] == 254 && Address->Addr[2] >= 1 && Address->Addr[2] <= 254));\r
939}\r
940\r
941/**\r
942 Determine if a IP4 address is unspecified.\r
943\r
944 @param[in] Address The address to test.\r
945\r
946 @retval TRUE It is.\r
947 @retval FALSE It is not.\r
948**/\r
949BOOLEAN\r
950PingNetIp4IsUnspecifiedAddr (\r
951 IN CONST EFI_IPv4_ADDRESS *Address\r
952 )\r
953{\r
954 return ((BOOLEAN)((ReadUnaligned32 ((UINT32 *)&Address->Addr[0])) == 0x00000000));\r
955}\r
956\r
957/**\r
958 Create a valid IP instance.\r
959\r
960 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
961\r
962 @retval EFI_SUCCESS Create a valid IPx instance successfully.\r
963 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.\r
964 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.\r
965 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
966 @retval EFI_NOT_FOUND The source address is not found.\r
967**/\r
968EFI_STATUS\r
969PingCreateIpInstance (\r
970 IN PING_PRIVATE_DATA *Private\r
971 )\r
972{\r
973 EFI_STATUS Status;\r
974 UINTN HandleIndex;\r
975 UINTN HandleNum;\r
976 EFI_HANDLE *HandleBuffer;\r
977 BOOLEAN UnspecifiedSrc;\r
978 EFI_STATUS MediaStatus;\r
979 EFI_SERVICE_BINDING_PROTOCOL *EfiSb;\r
980 VOID *IpXCfg;\r
981 EFI_IP6_CONFIG_DATA Ip6Config;\r
982 EFI_IP4_CONFIG_DATA Ip4Config;\r
983 VOID *IpXInterfaceInfo;\r
984 UINTN IfInfoSize;\r
985 EFI_IPv6_ADDRESS *Addr;\r
986 UINTN AddrIndex;\r
987\r
988 HandleBuffer = NULL;\r
989 UnspecifiedSrc = FALSE;\r
990 MediaStatus = EFI_SUCCESS;\r
991 EfiSb = NULL;\r
992 IpXInterfaceInfo = NULL;\r
993 IfInfoSize = 0;\r
994\r
995 //\r
996 // Locate all the handles with ip6 service binding protocol.\r
997 //\r
998 Status = gBS->LocateHandleBuffer (\r
999 ByProtocol,\r
1000 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,\r
1001 NULL,\r
1002 &HandleNum,\r
1003 &HandleBuffer\r
1004 );\r
1005 if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) {\r
1006 return EFI_ABORTED;\r
1007 }\r
1008\r
1009 if ((Private->IpChoice == PING_IP_CHOICE_IP6) ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS *)&Private->SrcAddress) : \\r
1010 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS *)&Private->SrcAddress))\r
1011 {\r
1012 //\r
1013 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.\r
1014 //\r
1015 UnspecifiedSrc = TRUE;\r
1016 }\r
1017\r
1018 //\r
1019 // Source address is required when pinging a link-local address.\r
1020 //\r
1021 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1022 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {\r
1023 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);\r
1024 Status = EFI_INVALID_PARAMETER;\r
1025 goto ON_ERROR;\r
1026 }\r
1027 } else {\r
1028 ASSERT (Private->IpChoice == PING_IP_CHOICE_IP4);\r
1029 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {\r
1030 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);\r
1031 Status = EFI_INVALID_PARAMETER;\r
1032 goto ON_ERROR;\r
1033 }\r
1034 }\r
1035\r
1036 //\r
1037 // For each ip6 protocol, check interface addresses list.\r
1038 //\r
1039 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
1040 EfiSb = NULL;\r
1041 IpXInterfaceInfo = NULL;\r
1042 IfInfoSize = 0;\r
1043\r
1044 if (UnspecifiedSrc) {\r
1045 //\r
1046 // Check media.\r
1047 //\r
1048 NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);\r
1049 if (MediaStatus != EFI_SUCCESS) {\r
1050 //\r
1051 // Skip this one.\r
1052 //\r
1053 continue;\r
1054 }\r
1055 }\r
1056\r
1057 Status = gBS->HandleProtocol (\r
1058 HandleBuffer[HandleIndex],\r
1059 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,\r
1060 (VOID **)&EfiSb\r
1061 );\r
1062 if (EFI_ERROR (Status)) {\r
1063 goto ON_ERROR;\r
1064 }\r
1065\r
1066 //\r
1067 // Ip6config protocol and ip6 service binding protocol are installed\r
1068 // on the same handle.\r
1069 //\r
1070 Status = gBS->HandleProtocol (\r
1071 HandleBuffer[HandleIndex],\r
1072 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ConfigProtocolGuid : &gEfiIp4Config2ProtocolGuid,\r
1073 (VOID **)&IpXCfg\r
1074 );\r
1075\r
1076 if (EFI_ERROR (Status)) {\r
1077 goto ON_ERROR;\r
1078 }\r
1079\r
1080 //\r
1081 // Get the interface information size.\r
1082 //\r
1083 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1084 Status = ((EFI_IP6_CONFIG_PROTOCOL *)IpXCfg)->GetData (\r
1085 IpXCfg,\r
1086 Ip6ConfigDataTypeInterfaceInfo,\r
1087 &IfInfoSize,\r
1088 NULL\r
1089 );\r
1090 } else {\r
1091 Status = ((EFI_IP4_CONFIG2_PROTOCOL *)IpXCfg)->GetData (\r
1092 IpXCfg,\r
1093 Ip4Config2DataTypeInterfaceInfo,\r
1094 &IfInfoSize,\r
1095 NULL\r
1096 );\r
1097 }\r
1098\r
1099 //\r
1100 // Skip the ones not in current use.\r
1101 //\r
1102 if (Status == EFI_NOT_STARTED) {\r
1103 continue;\r
1104 }\r
1105\r
1106 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1107 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
1108 goto ON_ERROR;\r
1109 }\r
1110\r
1111 IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
1112\r
1113 if (IpXInterfaceInfo == NULL) {\r
1114 Status = EFI_OUT_OF_RESOURCES;\r
1115 goto ON_ERROR;\r
1116 }\r
1117\r
1118 //\r
1119 // Get the interface info.\r
1120 //\r
1121 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1122 Status = ((EFI_IP6_CONFIG_PROTOCOL *)IpXCfg)->GetData (\r
1123 IpXCfg,\r
1124 Ip6ConfigDataTypeInterfaceInfo,\r
1125 &IfInfoSize,\r
1126 IpXInterfaceInfo\r
1127 );\r
1128 } else {\r
1129 Status = ((EFI_IP4_CONFIG2_PROTOCOL *)IpXCfg)->GetData (\r
1130 IpXCfg,\r
1131 Ip4Config2DataTypeInterfaceInfo,\r
1132 &IfInfoSize,\r
1133 IpXInterfaceInfo\r
1134 );\r
1135 }\r
1136\r
1137 if (EFI_ERROR (Status)) {\r
1138 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
1139 goto ON_ERROR;\r
1140 }\r
1141\r
1142 //\r
1143 // Check whether the source address is one of the interface addresses.\r
1144 //\r
1145 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1146 for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO *)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) {\r
1147 Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO *)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address);\r
1148\r
1149 if (UnspecifiedSrc) {\r
1150 if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {\r
1151 //\r
1152 // Select the interface automatically.\r
1153 //\r
1154 CopyMem (&Private->SrcAddress, Addr, sizeof (Private->SrcAddress));\r
1155 break;\r
1156 }\r
1157 } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
1158 //\r
1159 // Match a certain interface address.\r
1160 //\r
1161 break;\r
1162 }\r
1163 }\r
1164\r
1165 if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO *)IpXInterfaceInfo)->AddressInfoCount) {\r
1166 //\r
1167 // Found a nic handle with right interface address.\r
1168 //\r
1169 break;\r
1170 }\r
1171 } else {\r
1172 if (UnspecifiedSrc) {\r
1173 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress) &&\r
1174 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress))\r
1175 {\r
1176 //\r
1177 // Select the interface automatically.\r
1178 //\r
1179 break;\r
1180 }\r
1181 } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress)) {\r
1182 //\r
1183 // Match a certain interface address.\r
1184 //\r
1185 break;\r
1186 }\r
1187 }\r
1188\r
1189 FreePool (IpXInterfaceInfo);\r
1190 IpXInterfaceInfo = NULL;\r
1191 }\r
1192\r
1193 //\r
1194 // No exact interface address matched.\r
1195 //\r
1196\r
1197 if (HandleIndex == HandleNum) {\r
1198 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping");\r
1199 Status = EFI_NOT_FOUND;\r
1200 goto ON_ERROR;\r
1201 }\r
1202\r
1203 Private->NicHandle = HandleBuffer[HandleIndex];\r
1204\r
1205 ASSERT (EfiSb != NULL);\r
1206 Status = EfiSb->CreateChild (EfiSb, &Private->IpChildHandle);\r
1207\r
1208 if (EFI_ERROR (Status)) {\r
1209 goto ON_ERROR;\r
1210 }\r
1211\r
1212 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1213 Status = gBS->OpenProtocol (\r
1214 Private->IpChildHandle,\r
1215 &gEfiIp6ProtocolGuid,\r
1216 &Private->IpProtocol,\r
1217 gImageHandle,\r
1218 Private->IpChildHandle,\r
1219 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1220 );\r
1221 if (EFI_ERROR (Status)) {\r
1222 goto ON_ERROR;\r
1223 }\r
1224\r
1225 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
1226\r
1227 //\r
1228 // Configure the ip6 instance for icmp6 packet exchange.\r
1229 //\r
1230 Ip6Config.DefaultProtocol = 58;\r
1231 Ip6Config.AcceptAnyProtocol = FALSE;\r
1232 Ip6Config.AcceptIcmpErrors = TRUE;\r
1233 Ip6Config.AcceptPromiscuous = FALSE;\r
1234 Ip6Config.TrafficClass = 0;\r
1235 Ip6Config.HopLimit = 128;\r
1236 Ip6Config.FlowLabel = 0;\r
1237 Ip6Config.ReceiveTimeout = 0;\r
1238 Ip6Config.TransmitTimeout = 0;\r
1239\r
1240 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
1241 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
1242\r
1243 Status = ((EFI_IP6_PROTOCOL *)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config);\r
1244\r
1245 if (EFI_ERROR (Status)) {\r
1246 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
1247 goto ON_ERROR;\r
1248 }\r
1249\r
1250 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Transmit;\r
1251 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Receive;\r
1252 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Cancel;\r
1253 Private->ProtocolPointers.Poll = (PING_IPX_POLL)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Poll;\r
1254 } else {\r
1255 Status = gBS->OpenProtocol (\r
1256 Private->IpChildHandle,\r
1257 &gEfiIp4ProtocolGuid,\r
1258 &Private->IpProtocol,\r
1259 gImageHandle,\r
1260 Private->IpChildHandle,\r
1261 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1262 );\r
1263 if (EFI_ERROR (Status)) {\r
1264 goto ON_ERROR;\r
1265 }\r
1266\r
1267 ZeroMem (&Ip4Config, sizeof (EFI_IP4_CONFIG_DATA));\r
1268\r
1269 //\r
1270 // Configure the ip4 instance for icmp4 packet exchange.\r
1271 //\r
1272 Ip4Config.DefaultProtocol = 1;\r
1273 Ip4Config.AcceptAnyProtocol = FALSE;\r
1274 Ip4Config.AcceptBroadcast = FALSE;\r
1275 Ip4Config.AcceptIcmpErrors = TRUE;\r
1276 Ip4Config.AcceptPromiscuous = FALSE;\r
1277 Ip4Config.DoNotFragment = FALSE;\r
1278 Ip4Config.RawData = FALSE;\r
1279 Ip4Config.ReceiveTimeout = 0;\r
1280 Ip4Config.TransmitTimeout = 0;\r
1281 Ip4Config.UseDefaultAddress = TRUE;\r
1282 Ip4Config.TimeToLive = 128;\r
1283 Ip4Config.TypeOfService = 0;\r
1284\r
1285 Status = ((EFI_IP4_PROTOCOL *)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config);\r
1286\r
1287 if (EFI_ERROR (Status)) {\r
1288 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
1289 goto ON_ERROR;\r
1290 }\r
1291\r
1292 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Transmit;\r
1293 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Receive;\r
1294 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Cancel;\r
1295 Private->ProtocolPointers.Poll = (PING_IPX_POLL)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Poll;\r
1296 }\r
1297\r
1298 if (HandleBuffer != NULL) {\r
1299 FreePool (HandleBuffer);\r
1300 }\r
1301\r
1302 return EFI_SUCCESS;\r
1303\r
1304ON_ERROR:\r
1305 if (HandleBuffer != NULL) {\r
1306 FreePool (HandleBuffer);\r
1307 }\r
1308\r
1309 if (IpXInterfaceInfo != NULL) {\r
1310 FreePool (IpXInterfaceInfo);\r
1311 }\r
1312\r
1313 if ((EfiSb != NULL) && (Private->IpChildHandle != NULL)) {\r
1314 EfiSb->DestroyChild (EfiSb, Private->IpChildHandle);\r
1315 }\r
1316\r
1317 return Status;\r
1318}\r
1319\r
1320/**\r
1321 Destroy the IP instance.\r
1322\r
1323 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
1324\r
1325**/\r
1326VOID\r
1327Ping6DestroyIp6Instance (\r
1328 IN PING_PRIVATE_DATA *Private\r
1329 )\r
1330{\r
1331 EFI_STATUS Status;\r
1332 EFI_SERVICE_BINDING_PROTOCOL *IpSb;\r
1333\r
1334 gBS->CloseProtocol (\r
1335 Private->IpChildHandle,\r
1336 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ProtocolGuid : &gEfiIp4ProtocolGuid,\r
1337 gImageHandle,\r
1338 Private->IpChildHandle\r
1339 );\r
1340\r
1341 Status = gBS->HandleProtocol (\r
1342 Private->NicHandle,\r
1343 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,\r
1344 (VOID **)&IpSb\r
1345 );\r
1346\r
1347 if (!EFI_ERROR (Status)) {\r
1348 IpSb->DestroyChild (IpSb, Private->IpChildHandle);\r
1349 }\r
1350}\r
1351\r
1352/**\r
1353 The Ping Process.\r
1354\r
1355 @param[in] SendNumber The send request count.\r
1356 @param[in] BufferSize The send buffer size.\r
1357 @param[in] SrcAddress The source address.\r
1358 @param[in] DstAddress The destination address.\r
1359 @param[in] IpChoice The choice between IPv4 and IPv6.\r
1360\r
1361 @retval SHELL_SUCCESS The ping processed successfullly.\r
1362 @retval others The ping processed unsuccessfully.\r
1363**/\r
1364SHELL_STATUS\r
1365ShellPing (\r
1366 IN UINT32 SendNumber,\r
1367 IN UINT32 BufferSize,\r
1368 IN EFI_IPv6_ADDRESS *SrcAddress,\r
1369 IN EFI_IPv6_ADDRESS *DstAddress,\r
1370 IN UINT32 IpChoice\r
1371 )\r
1372{\r
1373 EFI_STATUS Status;\r
1374 PING_PRIVATE_DATA *Private;\r
1375 PING_ICMPX_TX_INFO *TxInfo;\r
1376 LIST_ENTRY *Entry;\r
1377 LIST_ENTRY *NextEntry;\r
1378 SHELL_STATUS ShellStatus;\r
1379\r
1380 ShellStatus = SHELL_SUCCESS;\r
1381 Private = AllocateZeroPool (sizeof (PING_PRIVATE_DATA));\r
1382\r
1383 if (Private == NULL) {\r
1384 return (SHELL_OUT_OF_RESOURCES);\r
1385 }\r
1386\r
1387 Private->IpChoice = IpChoice;\r
1388 Private->Signature = PING_PRIVATE_DATA_SIGNATURE;\r
1389 Private->SendNum = SendNumber;\r
1390 Private->BufferSize = BufferSize;\r
1391 Private->RttMin = ~((UINT64)(0x0));\r
1392 Private->Status = EFI_NOT_READY;\r
1393\r
1394 CopyMem (&Private->SrcAddress, SrcAddress, sizeof (Private->SrcAddress));\r
1395 CopyMem (&Private->DstAddress, DstAddress, sizeof (Private->DstAddress));\r
1396\r
1397 InitializeListHead (&Private->TxList);\r
1398\r
1399 //\r
1400 // Open and configure a ip instance for us.\r
1401 //\r
1402 Status = PingCreateIpInstance (Private);\r
1403\r
1404 if (EFI_ERROR (Status)) {\r
1405 ShellStatus = SHELL_ACCESS_DENIED;\r
1406 goto ON_EXIT;\r
1407 }\r
1408\r
1409 //\r
1410 // Print the command line itself.\r
1411 //\r
1412 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_START), gShellNetwork1HiiHandle, mDstString, Private->BufferSize);\r
1413 //\r
1414 // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
1415 //\r
1416 Status = Ping6ReceiveEchoReply (Private);\r
1417\r
1418 if (EFI_ERROR (Status)) {\r
1419 ShellStatus = SHELL_ACCESS_DENIED;\r
1420 goto ON_EXIT;\r
1421 }\r
1422\r
1423 //\r
1424 // Create and start timer to send icmp6 echo request packet per second.\r
1425 //\r
1426 Status = gBS->CreateEvent (\r
1427 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1428 TPL_CALLBACK,\r
1429 Ping6OnTimerRoutine,\r
1430 Private,\r
1431 &Private->Timer\r
1432 );\r
1433\r
1434 if (EFI_ERROR (Status)) {\r
1435 ShellStatus = SHELL_ACCESS_DENIED;\r
1436 goto ON_EXIT;\r
1437 }\r
1438\r
1439 //\r
1440 // Start a timer to calculate the RTT.\r
1441 //\r
1442 Status = PingInitRttTimer (Private);\r
1443 if (EFI_ERROR (Status)) {\r
1444 ShellStatus = SHELL_ACCESS_DENIED;\r
1445 goto ON_EXIT;\r
1446 }\r
1447\r
1448 //\r
1449 // Create a ipv6 token to send the first icmp6 echo request packet.\r
1450 //\r
1451 Status = PingSendEchoRequest (Private);\r
1452 //\r
1453 // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
1454 //\r
1455 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
1456 ShellStatus = SHELL_ACCESS_DENIED;\r
1457 if (Status == EFI_NOT_FOUND) {\r
1458 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOSOURCE_INDO), gShellNetwork1HiiHandle, mDstString);\r
1459 } else if (Status == RETURN_NO_MAPPING) {\r
1460 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString);\r
1461 } else {\r
1462 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, L"ping", Status);\r
1463 }\r
1464\r
1465 goto ON_EXIT;\r
1466 }\r
1467\r
1468 Status = gBS->SetTimer (\r
1469 Private->Timer,\r
1470 TimerPeriodic,\r
1471 ONE_SECOND\r
1472 );\r
1473\r
1474 if (EFI_ERROR (Status)) {\r
1475 ShellStatus = SHELL_ACCESS_DENIED;\r
1476 goto ON_EXIT;\r
1477 }\r
1478\r
1479 //\r
1480 // Control the ping6 process by two factors:\r
1481 // 1. Hot key\r
1482 // 2. Private->Status\r
1483 // 2.1. success means all icmp6 echo request packets get reply packets.\r
1484 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
1485 // 2.3. noready means ping6 process is on-the-go.\r
1486 //\r
1487 while (Private->Status == EFI_NOT_READY) {\r
1488 Status = Private->ProtocolPointers.Poll (Private->IpProtocol);\r
1489 if (ShellGetExecutionBreakFlag ()) {\r
1490 Private->Status = EFI_ABORTED;\r
1491 goto ON_STAT;\r
1492 }\r
1493 }\r
1494\r
1495ON_STAT:\r
1496 //\r
1497 // Display the statistics in all.\r
1498 //\r
1499 gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
1500\r
1501 if (Private->TxCount != 0) {\r
1502 ShellPrintHiiEx (\r
1503 -1,\r
1504 -1,\r
1505 NULL,\r
1506 STRING_TOKEN (STR_PING_STAT),\r
1507 gShellNetwork1HiiHandle,\r
1508 Private->TxCount,\r
1509 (Private->RxCount - Private->FailedCount),\r
1510 (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)),\r
1511 Private->RttSum\r
1512 );\r
1513 }\r
1514\r
1515 if (Private->RxCount > Private->FailedCount) {\r
1516 ShellPrintHiiEx (\r
1517 -1,\r
1518 -1,\r
1519 NULL,\r
1520 STRING_TOKEN (STR_PING_RTT),\r
1521 gShellNetwork1HiiHandle,\r
1522 Private->RttMin,\r
1523 Private->RttMin + Private->TimerPeriod,\r
1524 Private->RttMax,\r
1525 Private->RttMax + Private->TimerPeriod,\r
1526 DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL),\r
1527 DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod\r
1528 );\r
1529 }\r
1530\r
1531ON_EXIT:\r
1532\r
1533 if (Private != NULL) {\r
1534 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
1535 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
1536\r
1537 if ((Private->IpProtocol != NULL) && (Private->ProtocolPointers.Cancel != NULL)) {\r
1538 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
1539 }\r
1540\r
1541 RemoveEntryList (&TxInfo->Link);\r
1542 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
1543 }\r
1544\r
1545 PingFreeRttTimer (Private);\r
1546\r
1547 if (Private->Timer != NULL) {\r
1548 gBS->CloseEvent (Private->Timer);\r
1549 }\r
1550\r
1551 if ((Private->IpProtocol != NULL) && (Private->ProtocolPointers.Cancel != NULL)) {\r
1552 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, &Private->RxToken);\r
1553 }\r
1554\r
1555 if (Private->RxToken.Event != NULL) {\r
1556 gBS->CloseEvent (Private->RxToken.Event);\r
1557 }\r
1558\r
1559 if (Private->IpChildHandle != NULL) {\r
1560 Ping6DestroyIp6Instance (Private);\r
1561 }\r
1562\r
1563 FreePool (Private);\r
1564 }\r
1565\r
1566 return ShellStatus;\r
1567}\r
1568\r
1569/**\r
1570 Function for 'ping' command.\r
1571\r
1572 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
1573 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
1574\r
1575 @retval SHELL_SUCCESS The ping processed successfullly.\r
1576 @retval others The ping processed unsuccessfully.\r
1577\r
1578**/\r
1579SHELL_STATUS\r
1580EFIAPI\r
1581ShellCommandRunPing (\r
1582 IN EFI_HANDLE ImageHandle,\r
1583 IN EFI_SYSTEM_TABLE *SystemTable\r
1584 )\r
1585{\r
1586 EFI_STATUS Status;\r
1587 SHELL_STATUS ShellStatus;\r
1588 EFI_IPv6_ADDRESS DstAddress;\r
1589 EFI_IPv6_ADDRESS SrcAddress;\r
1590 UINT64 BufferSize;\r
1591 UINTN SendNumber;\r
1592 LIST_ENTRY *ParamPackage;\r
1593 CONST CHAR16 *ValueStr;\r
1594 UINTN NonOptionCount;\r
1595 UINT32 IpChoice;\r
1596 CHAR16 *ProblemParam;\r
1597\r
1598 //\r
1599 // we use IPv6 buffers to hold items...\r
1600 // make sure this is enough space!\r
1601 //\r
1602 ASSERT (sizeof (EFI_IPv4_ADDRESS) <= sizeof (EFI_IPv6_ADDRESS));\r
1603 ASSERT (sizeof (EFI_IP4_COMPLETION_TOKEN) <= sizeof (EFI_IP6_COMPLETION_TOKEN));\r
1604\r
1605 IpChoice = PING_IP_CHOICE_IP4;\r
1606\r
1607 ShellStatus = SHELL_SUCCESS;\r
1608 ProblemParam = NULL;\r
1609\r
1610 Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);\r
1611 if (EFI_ERROR (Status)) {\r
1612 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);\r
1613 ShellStatus = SHELL_INVALID_PARAMETER;\r
1614 goto ON_EXIT;\r
1615 }\r
1616\r
1617 if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) {\r
1618 IpChoice = PING_IP_CHOICE_IP6;\r
1619 }\r
1620\r
1621 //\r
1622 // Parse the parameter of count number.\r
1623 //\r
1624 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
1625 if (ValueStr != NULL) {\r
1626 SendNumber = ShellStrToUintn (ValueStr);\r
1627\r
1628 //\r
1629 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1630 //\r
1631 if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) {\r
1632 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
1633 ShellStatus = SHELL_INVALID_PARAMETER;\r
1634 goto ON_EXIT;\r
1635 }\r
1636 } else {\r
1637 SendNumber = DEFAULT_SEND_COUNT;\r
1638 }\r
1639\r
1640 //\r
1641 // Parse the parameter of buffer size.\r
1642 //\r
1643 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
1644 if (ValueStr != NULL) {\r
1645 BufferSize = ShellStrToUintn (ValueStr);\r
1646\r
1647 //\r
1648 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1649 //\r
1650 if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) {\r
1651 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
1652 ShellStatus = SHELL_INVALID_PARAMETER;\r
1653 goto ON_EXIT;\r
1654 }\r
1655 } else {\r
1656 BufferSize = DEFAULT_BUFFER_SIZE;\r
1657 }\r
1658\r
1659 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
1660 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
1661\r
1662 //\r
1663 // Parse the parameter of source ip address.\r
1664 //\r
1665 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
1666 if (ValueStr == NULL) {\r
1667 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s");\r
1668 }\r
1669\r
1670 if (ValueStr != NULL) {\r
1671 mSrcString = ValueStr;\r
1672 if (IpChoice == PING_IP_CHOICE_IP6) {\r
1673 Status = NetLibStrToIp6 (ValueStr, &SrcAddress);\r
1674 } else {\r
1675 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS *)&SrcAddress);\r
1676 }\r
1677\r
1678 if (EFI_ERROR (Status)) {\r
1679 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
1680 ShellStatus = SHELL_INVALID_PARAMETER;\r
1681 goto ON_EXIT;\r
1682 }\r
1683 }\r
1684\r
1685 //\r
1686 // Parse the parameter of destination ip address.\r
1687 //\r
1688 NonOptionCount = ShellCommandLineGetCount (ParamPackage);\r
1689 if (NonOptionCount < 2) {\r
1690 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping");\r
1691 ShellStatus = SHELL_INVALID_PARAMETER;\r
1692 goto ON_EXIT;\r
1693 }\r
1694\r
1695 if (NonOptionCount > 2) {\r
1696 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping");\r
1697 ShellStatus = SHELL_INVALID_PARAMETER;\r
1698 goto ON_EXIT;\r
1699 }\r
1700\r
1701 ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);\r
1702 if (ValueStr != NULL) {\r
1703 mDstString = ValueStr;\r
1704 if (IpChoice == PING_IP_CHOICE_IP6) {\r
1705 Status = NetLibStrToIp6 (ValueStr, &DstAddress);\r
1706 } else {\r
1707 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS *)&DstAddress);\r
1708 }\r
1709\r
1710 if (EFI_ERROR (Status)) {\r
1711 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
1712 ShellStatus = SHELL_INVALID_PARAMETER;\r
1713 goto ON_EXIT;\r
1714 }\r
1715 }\r
1716\r
1717 //\r
1718 // Enter into ping process.\r
1719 //\r
1720 ShellStatus = ShellPing (\r
1721 (UINT32)SendNumber,\r
1722 (UINT32)BufferSize,\r
1723 &SrcAddress,\r
1724 &DstAddress,\r
1725 IpChoice\r
1726 );\r
1727\r
1728ON_EXIT:\r
1729 ShellCommandLineFreeVarList (ParamPackage);\r
1730 return ShellStatus;\r
1731}\r