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