]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
ShellPkg: Fix Ping GetTimerPeriod API failure
[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
8a576733 262 UINT32 TimerPeriod;\r
e0c2cc6f 263\r
2a326330 264 RttTimerTick = 0;\r
47d20b54 265 StallCounter = 0;\r
8a576733 266 TimerPeriod = 0;\r
e0c2cc6f 267\r
2a326330
FS
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
e0c2cc6f 275 if (EFI_ERROR (Status)) {\r
2a326330
FS
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
e0c2cc6f 293 }\r
e0c2cc6f 294\r
2a326330
FS
295 gBS->RestoreTPL (OldTpl);\r
296\r
297 gBS->SetTimer (TimerEvent, TimerCancel, 0);\r
298 gBS->CloseEvent (TimerEvent);\r
299\r
8a576733
RM
300 TimerPeriod = StallCounter / RttTimerTick;\r
301 if (TimerPeriod != 0) {\r
302 return TimerPeriod;\r
303 } else {\r
304 return 1;\r
305 }\r
2a326330 306}\r
68fb0527 307\r
308/**\r
2a326330 309 Initialize the timer event for RTT (round trip time).\r
68fb0527 310\r
2a326330
FS
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
68fb0527 315\r
316**/\r
317EFI_STATUS\r
2a326330 318PingInitRttTimer (\r
47d20b54 319 PING_PRIVATE_DATA *Private\r
68fb0527 320 )\r
321{\r
47d20b54 322 EFI_STATUS Status;\r
2a326330
FS
323\r
324 Private->TimerPeriod = GetTimerPeriod ();\r
325 if (Private->TimerPeriod == 0) {\r
326 return EFI_ABORTED;\r
327 }\r
ba0014b9 328\r
2a326330 329 Private->RttTimerTick = 0;\r
47d20b54
MK
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
2a326330
FS
337 if (EFI_ERROR (Status)) {\r
338 return Status;\r
339 }\r
68fb0527 340\r
2a326330
FS
341 Status = gBS->SetTimer (\r
342 Private->RttTimer,\r
343 TimerPeriodic,\r
344 TICKS_PER_MS\r
345 );\r
68fb0527 346 if (EFI_ERROR (Status)) {\r
2a326330 347 gBS->CloseEvent (Private->RttTimer);\r
68fb0527 348 return Status;\r
349 }\r
350\r
2a326330
FS
351 return EFI_SUCCESS;\r
352}\r
68fb0527 353\r
2a326330
FS
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
47d20b54 362 PING_PRIVATE_DATA *Private\r
2a326330
FS
363 )\r
364{\r
365 if (Private->RttTimer != NULL) {\r
366 gBS->SetTimer (Private->RttTimer, TimerCancel, 0);\r
367 gBS->CloseEvent (Private->RttTimer);\r
68fb0527 368 }\r
2a326330 369}\r
68fb0527 370\r
2a326330
FS
371/**\r
372 Read the current time.\r
ba0014b9 373\r
2a326330 374 @param[in] Private The pointer to PING_PRIVATE_DATA.\r
68fb0527 375\r
2a326330
FS
376 @retval the current tick value.\r
377**/\r
378UINT32\r
379ReadTime (\r
47d20b54 380 PING_PRIVATE_DATA *Private\r
2a326330
FS
381 )\r
382{\r
383 return Private->RttTimerTick;\r
68fb0527 384}\r
385\r
386/**\r
85efb9d8 387 Calculate a duration in ms.\r
68fb0527 388\r
2a326330
FS
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
68fb0527 392\r
393 @return The duration in ms.\r
394 @retval 0 The parameters were not valid.\r
395**/\r
2a326330 396UINT32\r
68fb0527 397CalculateTick (\r
47d20b54
MK
398 PING_PRIVATE_DATA *Private,\r
399 IN UINT32 Begin,\r
400 IN UINT32 End\r
68fb0527 401 )\r
402{\r
2a326330 403 if (End < Begin) {\r
68fb0527 404 return (0);\r
405 }\r
2a326330
FS
406\r
407 return (End - Begin) * Private->TimerPeriod;\r
68fb0527 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
68fb0527 417PingDestroyTxInfo (\r
47d20b54
MK
418 IN PING_ICMPX_TX_INFO *TxInfo,\r
419 IN UINT32 IpChoice\r
68fb0527 420 )\r
421{\r
47d20b54
MK
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
68fb0527 426\r
427 if (TxInfo == NULL) {\r
428 return;\r
429 }\r
430\r
431 if (TxInfo->Token != NULL) {\r
68fb0527 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
68fb0527 487Ping6MatchEchoReply (\r
47d20b54
MK
488 IN PING_PRIVATE_DATA *Private,\r
489 IN ICMPX_ECHO_REQUEST_REPLY *Packet\r
68fb0527 490 )\r
491{\r
47d20b54
MK
492 PING_ICMPX_TX_INFO *TxInfo;\r
493 LIST_ENTRY *Entry;\r
494 LIST_ENTRY *NextEntry;\r
68fb0527 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
47d20b54
MK
523 IN EFI_EVENT Event,\r
524 IN VOID *Context\r
68fb0527 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
47d20b54
MK
539 IN EFI_EVENT Event,\r
540 IN VOID *Context\r
68fb0527 541 )\r
542{\r
47d20b54
MK
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
68fb0527 548\r
47d20b54 549 Private = (PING_PRIVATE_DATA *)Context;\r
68fb0527 550\r
47d20b54 551 if ((Private == NULL) || (Private->Status == EFI_ABORTED) || (Private->Signature != PING_PRIVATE_DATA_SIGNATURE)) {\r
68fb0527 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
47d20b54
MK
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
68fb0527 563 goto ON_EXIT;\r
564 }\r
47d20b54
MK
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
68fb0527 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
47d20b54
MK
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
68fb0527 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
ba0014b9 588\r
68fb0527 589 if (PayLoad != Private->BufferSize) {\r
590 goto ON_EXIT;\r
591 }\r
47d20b54 592\r
68fb0527 593 //\r
594 // Check whether the reply matches the sent request before.\r
595 //\r
596 Status = Ping6MatchEchoReply (Private, Reply);\r
47d20b54 597 if (EFI_ERROR (Status)) {\r
68fb0527 598 goto ON_EXIT;\r
599 }\r
47d20b54 600\r
68fb0527 601 //\r
602 // Display statistics on this icmp6 echo reply packet.\r
603 //\r
47d20b54 604 Rtt = CalculateTick (Private, Reply->TimeStamp, ReadTime (Private));\r
68fb0527 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
47d20b54 619 Private->IpChoice == PING_IP_CHOICE_IP6 ? ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->HopLimit : 0,\r
2a326330
FS
620 Rtt,\r
621 Rtt + Private->TimerPeriod\r
68fb0527 622 );\r
623\r
624ON_EXIT:\r
625\r
65c73df4
MR
626 //\r
627 // Recycle the packet before reusing RxToken\r
628 //\r
47d20b54 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
65c73df4 630\r
68fb0527 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
5d8aa7eb 640 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);\r
68fb0527 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
68fb0527 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
68fb0527 662PingGenerateToken (\r
47d20b54
MK
663 IN PING_PRIVATE_DATA *Private,\r
664 IN UINT32 TimeStamp,\r
665 IN UINT16 SequenceNum\r
68fb0527 666 )\r
667{\r
47d20b54
MK
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
68fb0527 674\r
675 Request = AllocateZeroPool (Private->BufferSize);\r
676 if (Request == NULL) {\r
677 return NULL;\r
678 }\r
47d20b54
MK
679\r
680 TxData = AllocateZeroPool (Private->IpChoice == PING_IP_CHOICE_IP6 ? sizeof (EFI_IP6_TRANSMIT_DATA) : sizeof (EFI_IP4_TRANSMIT_DATA));\r
68fb0527 681 if (TxData == NULL) {\r
682 FreePool (Request);\r
683 return NULL;\r
684 }\r
47d20b54 685\r
68fb0527 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
47d20b54 696 Request->Type = (UINT8)(Private->IpChoice == PING_IP_CHOICE_IP6 ? ICMP_V6_ECHO_REQUEST : ICMP_V4_ECHO_REQUEST);\r
68fb0527 697 Request->Code = 0;\r
ba0014b9 698 Request->SequenceNum = SequenceNum;\r
68fb0527 699 Request->Identifier = 0;\r
700 Request->Checksum = 0;\r
701\r
702 //\r
703 // Assembly token for transmit.\r
704 //\r
47d20b54
MK
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
68fb0527 714 } else {\r
47d20b54
MK
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
68fb0527 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
68fb0527 765PingSendEchoRequest (\r
47d20b54 766 IN PING_PRIVATE_DATA *Private\r
68fb0527 767 )\r
768{\r
47d20b54
MK
769 EFI_STATUS Status;\r
770 PING_ICMPX_TX_INFO *TxInfo;\r
68fb0527 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
2a326330 778 TxInfo->TimeStamp = ReadTime (Private);\r
47d20b54 779 TxInfo->SequenceNum = (UINT16)(Private->TxCount + 1);\r
68fb0527 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
47d20b54 791 ASSERT (Private->ProtocolPointers.Transmit != NULL);\r
d624deb7
MA
792\r
793 InsertTailList (&Private->TxList, &TxInfo->Link);\r
794\r
68fb0527 795 Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);\r
796\r
797 if (EFI_ERROR (Status)) {\r
d624deb7 798 RemoveEntryList (&TxInfo->Link);\r
68fb0527 799 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
800 return Status;\r
801 }\r
802\r
68fb0527 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
68fb0527 818Ping6ReceiveEchoReply (\r
47d20b54 819 IN PING_PRIVATE_DATA *Private\r
68fb0527 820 )\r
821{\r
47d20b54 822 EFI_STATUS Status;\r
68fb0527 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
5d8aa7eb
FS
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
47d20b54 844\r
5d8aa7eb 845 return Status;\r
68fb0527 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
47d20b54
MK
858 IN EFI_EVENT Event,\r
859 IN VOID *Context\r
68fb0527 860 )\r
861{\r
47d20b54
MK
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
68fb0527 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
68fb0527 879 Status = PingSendEchoRequest (Private);\r
47d20b54 880 if (Private->TxCount != 0) {\r
68fb0527 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
47d20b54 886\r
68fb0527 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
2a326330 892 Time = CalculateTick (Private, TxInfo->TimeStamp, ReadTime (Private));\r
68fb0527 893\r
894 //\r
895 // Remove the timeout echo request from txlist.\r
896 //\r
897 if (Time > DEFAULT_TIMEOUT) {\r
68fb0527 898 if (EFI_ERROR (TxInfo->Token->Status)) {\r
899 Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
900 }\r
47d20b54 901\r
68fb0527 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
80f7a8f5
SSESPS
910 Private->RxCount++;\r
911 Private->FailedCount++;\r
912\r
68fb0527 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
68fb0527 934PingNetIp4IsLinkLocalAddr (\r
47d20b54 935 IN CONST EFI_IPv4_ADDRESS *Address\r
68fb0527 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
68fb0527 950PingNetIp4IsUnspecifiedAddr (\r
47d20b54 951 IN CONST EFI_IPv4_ADDRESS *Address\r
68fb0527 952 )\r
953{\r
47d20b54 954 return ((BOOLEAN)((ReadUnaligned32 ((UINT32 *)&Address->Addr[0])) == 0x00000000));\r
68fb0527 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
68fb0527 969PingCreateIpInstance (\r
47d20b54 970 IN PING_PRIVATE_DATA *Private\r
68fb0527 971 )\r
972{\r
47d20b54
MK
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
68fb0527 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
47d20b54 1000 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,\r
68fb0527 1001 NULL,\r
1002 &HandleNum,\r
1003 &HandleBuffer\r
1004 );\r
33c031ee 1005 if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) {\r
68fb0527 1006 return EFI_ABORTED;\r
1007 }\r
9ce14ca1 1008\r
47d20b54
MK
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
9ce14ca1 1012 //\r
ba0014b9 1013 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.\r
9ce14ca1
JW
1014 //\r
1015 UnspecifiedSrc = TRUE;\r
1016 }\r
ba0014b9 1017\r
68fb0527 1018 //\r
9ce14ca1 1019 // Source address is required when pinging a link-local address.\r
68fb0527 1020 //\r
1021 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
47d20b54 1022 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {\r
9ce14ca1 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 } else {\r
47d20b54
MK
1028 ASSERT (Private->IpChoice == PING_IP_CHOICE_IP4);\r
1029 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {\r
ba0014b9 1030 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);\r
68fb0527 1031 Status = EFI_INVALID_PARAMETER;\r
1032 goto ON_ERROR;\r
1033 }\r
1034 }\r
ba0014b9 1035\r
68fb0527 1036 //\r
1037 // For each ip6 protocol, check interface addresses list.\r
1038 //\r
1039 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
47d20b54
MK
1040 EfiSb = NULL;\r
1041 IpXInterfaceInfo = NULL;\r
1042 IfInfoSize = 0;\r
68fb0527 1043\r
9ce14ca1
JW
1044 if (UnspecifiedSrc) {\r
1045 //\r
1046 // Check media.\r
1047 //\r
0f1e07ee 1048 NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);\r
1049 if (MediaStatus != EFI_SUCCESS) {\r
9ce14ca1
JW
1050 //\r
1051 // Skip this one.\r
1052 //\r
1053 continue;\r
1054 }\r
1055 }\r
1056\r
68fb0527 1057 Status = gBS->HandleProtocol (\r
1058 HandleBuffer[HandleIndex],\r
47d20b54
MK
1059 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,\r
1060 (VOID **)&EfiSb\r
68fb0527 1061 );\r
1062 if (EFI_ERROR (Status)) {\r
1063 goto ON_ERROR;\r
1064 }\r
1065\r
9ce14ca1
JW
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
47d20b54
MK
1072 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ConfigProtocolGuid : &gEfiIp4Config2ProtocolGuid,\r
1073 (VOID **)&IpXCfg\r
9ce14ca1 1074 );\r
68fb0527 1075\r
9ce14ca1
JW
1076 if (EFI_ERROR (Status)) {\r
1077 goto ON_ERROR;\r
1078 }\r
47d20b54 1079\r
9ce14ca1
JW
1080 //\r
1081 // Get the interface information size.\r
1082 //\r
1083 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
47d20b54
MK
1084 Status = ((EFI_IP6_CONFIG_PROTOCOL *)IpXCfg)->GetData (\r
1085 IpXCfg,\r
1086 Ip6ConfigDataTypeInterfaceInfo,\r
1087 &IfInfoSize,\r
1088 NULL\r
1089 );\r
9ce14ca1 1090 } else {\r
47d20b54
MK
1091 Status = ((EFI_IP4_CONFIG2_PROTOCOL *)IpXCfg)->GetData (\r
1092 IpXCfg,\r
1093 Ip4Config2DataTypeInterfaceInfo,\r
1094 &IfInfoSize,\r
1095 NULL\r
1096 );\r
9ce14ca1 1097 }\r
ba0014b9 1098\r
9ce14ca1
JW
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
68fb0527 1105\r
9ce14ca1
JW
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
68fb0527 1110\r
9ce14ca1 1111 IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
68fb0527 1112\r
9ce14ca1
JW
1113 if (IpXInterfaceInfo == NULL) {\r
1114 Status = EFI_OUT_OF_RESOURCES;\r
1115 goto ON_ERROR;\r
1116 }\r
47d20b54 1117\r
9ce14ca1
JW
1118 //\r
1119 // Get the interface info.\r
1120 //\r
1121 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
47d20b54
MK
1122 Status = ((EFI_IP6_CONFIG_PROTOCOL *)IpXCfg)->GetData (\r
1123 IpXCfg,\r
1124 Ip6ConfigDataTypeInterfaceInfo,\r
1125 &IfInfoSize,\r
1126 IpXInterfaceInfo\r
1127 );\r
9ce14ca1 1128 } else {\r
47d20b54
MK
1129 Status = ((EFI_IP4_CONFIG2_PROTOCOL *)IpXCfg)->GetData (\r
1130 IpXCfg,\r
1131 Ip4Config2DataTypeInterfaceInfo,\r
1132 &IfInfoSize,\r
1133 IpXInterfaceInfo\r
1134 );\r
9ce14ca1 1135 }\r
68fb0527 1136\r
9ce14ca1
JW
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
47d20b54 1141\r
9ce14ca1
JW
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
47d20b54
MK
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
68fb0527 1148\r
9ce14ca1
JW
1149 if (UnspecifiedSrc) {\r
1150 if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {\r
68fb0527 1151 //\r
9ce14ca1 1152 // Select the interface automatically.\r
68fb0527 1153 //\r
47d20b54 1154 CopyMem (&Private->SrcAddress, Addr, sizeof (Private->SrcAddress));\r
68fb0527 1155 break;\r
1156 }\r
9ce14ca1 1157 } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
68fb0527 1158 //\r
9ce14ca1 1159 // Match a certain interface address.\r
68fb0527 1160 //\r
1161 break;\r
1162 }\r
9ce14ca1
JW
1163 }\r
1164\r
47d20b54 1165 if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO *)IpXInterfaceInfo)->AddressInfoCount) {\r
68fb0527 1166 //\r
9ce14ca1 1167 // Found a nic handle with right interface address.\r
68fb0527 1168 //\r
9ce14ca1
JW
1169 break;\r
1170 }\r
1171 } else {\r
1172 if (UnspecifiedSrc) {\r
47d20b54
MK
1173 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress) &&\r
1174 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress))\r
1175 {\r
68fb0527 1176 //\r
9ce14ca1 1177 // Select the interface automatically.\r
68fb0527 1178 //\r
1179 break;\r
1180 }\r
47d20b54 1181 } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress)) {\r
9ce14ca1
JW
1182 //\r
1183 // Match a certain interface address.\r
1184 //\r
1185 break;\r
68fb0527 1186 }\r
1187 }\r
1188\r
1189 FreePool (IpXInterfaceInfo);\r
1190 IpXInterfaceInfo = NULL;\r
1191 }\r
47d20b54 1192\r
68fb0527 1193 //\r
1194 // No exact interface address matched.\r
1195 //\r
1196\r
1197 if (HandleIndex == HandleNum) {\r
ba0014b9 1198 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping");\r
68fb0527 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
47d20b54 1211\r
68fb0527 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
68fb0527 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
47d20b54 1240 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
68fb0527 1241 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
1242\r
47d20b54 1243 Status = ((EFI_IP6_PROTOCOL *)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config);\r
68fb0527 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
47d20b54
MK
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
68fb0527 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
68fb0527 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
68fb0527 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
47d20b54 1285 Status = ((EFI_IP4_PROTOCOL *)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config);\r
68fb0527 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
47d20b54
MK
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
68fb0527 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
75dce340 1321 Destroy the IP instance.\r
68fb0527 1322\r
1323 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
1324\r
1325**/\r
1326VOID\r
75dce340 1327Ping6DestroyIp6Instance (\r
47d20b54 1328 IN PING_PRIVATE_DATA *Private\r
68fb0527 1329 )\r
1330{\r
47d20b54
MK
1331 EFI_STATUS Status;\r
1332 EFI_SERVICE_BINDING_PROTOCOL *IpSb;\r
68fb0527 1333\r
1334 gBS->CloseProtocol (\r
1335 Private->IpChildHandle,\r
47d20b54 1336 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ProtocolGuid : &gEfiIp4ProtocolGuid,\r
68fb0527 1337 gImageHandle,\r
1338 Private->IpChildHandle\r
1339 );\r
1340\r
1341 Status = gBS->HandleProtocol (\r
1342 Private->NicHandle,\r
47d20b54
MK
1343 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,\r
1344 (VOID **)&IpSb\r
68fb0527 1345 );\r
1346\r
47d20b54 1347 if (!EFI_ERROR (Status)) {\r
68fb0527 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
68fb0527 1365ShellPing (\r
47d20b54
MK
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
68fb0527 1371 )\r
1372{\r
47d20b54
MK
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
68fb0527 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
47d20b54
MK
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
68fb0527 1393\r
47d20b54
MK
1394 CopyMem (&Private->SrcAddress, SrcAddress, sizeof (Private->SrcAddress));\r
1395 CopyMem (&Private->DstAddress, DstAddress, sizeof (Private->DstAddress));\r
68fb0527 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
47d20b54 1408\r
68fb0527 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
47d20b54 1422\r
68fb0527 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
2a326330
FS
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
ba0014b9 1447\r
68fb0527 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
47d20b54 1457 if (Status == EFI_NOT_FOUND) {\r
68fb0527 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
ba0014b9 1462 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, L"ping", Status);\r
68fb0527 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
47d20b54 1478\r
68fb0527 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
47d20b54 1489 if (ShellGetExecutionBreakFlag ()) {\r
68fb0527 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
80f7a8f5
SSESPS
1509 (Private->RxCount - Private->FailedCount),\r
1510 (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)),\r
68fb0527 1511 Private->RttSum\r
1512 );\r
1513 }\r
1514\r
80f7a8f5 1515 if (Private->RxCount > Private->FailedCount) {\r
68fb0527 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
2a326330 1523 Private->RttMin + Private->TimerPeriod,\r
68fb0527 1524 Private->RttMax,\r
2a326330
FS
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
68fb0527 1528 );\r
1529 }\r
1530\r
1531ON_EXIT:\r
1532\r
1533 if (Private != NULL) {\r
68fb0527 1534 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
1535 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
1536\r
47d20b54 1537 if ((Private->IpProtocol != NULL) && (Private->ProtocolPointers.Cancel != NULL)) {\r
68fb0527 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
2a326330
FS
1545 PingFreeRttTimer (Private);\r
1546\r
68fb0527 1547 if (Private->Timer != NULL) {\r
1548 gBS->CloseEvent (Private->Timer);\r
1549 }\r
1550\r
47d20b54 1551 if ((Private->IpProtocol != NULL) && (Private->ProtocolPointers.Cancel != NULL)) {\r
68fb0527 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
75dce340 1560 Ping6DestroyIp6Instance (Private);\r
68fb0527 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
7c25b7ea 1574\r
1575 @retval SHELL_SUCCESS The ping processed successfullly.\r
1576 @retval others The ping processed unsuccessfully.\r
ba0014b9 1577\r
68fb0527 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
47d20b54
MK
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
68fb0527 1597\r
1598 //\r
ba0014b9 1599 // we use IPv6 buffers to hold items...\r
68fb0527 1600 // make sure this is enough space!\r
1601 //\r
47d20b54
MK
1602 ASSERT (sizeof (EFI_IPv4_ADDRESS) <= sizeof (EFI_IPv6_ADDRESS));\r
1603 ASSERT (sizeof (EFI_IP4_COMPLETION_TOKEN) <= sizeof (EFI_IP6_COMPLETION_TOKEN));\r
68fb0527 1604\r
1605 IpChoice = PING_IP_CHOICE_IP4;\r
1606\r
47d20b54 1607 ShellStatus = SHELL_SUCCESS;\r
ab7c10f2 1608 ProblemParam = NULL;\r
68fb0527 1609\r
ab7c10f2 1610 Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);\r
47d20b54 1611 if (EFI_ERROR (Status)) {\r
ab7c10f2 1612 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);\r
68fb0527 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
268d3445 1622 // Parse the parameter of count number.\r
68fb0527 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
ba0014b9 1632 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
68fb0527 1633 ShellStatus = SHELL_INVALID_PARAMETER;\r
1634 goto ON_EXIT;\r
1635 }\r
1636 } else {\r
1637 SendNumber = DEFAULT_SEND_COUNT;\r
1638 }\r
47d20b54 1639\r
68fb0527 1640 //\r
268d3445 1641 // Parse the parameter of buffer size.\r
68fb0527 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
ba0014b9 1651 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
68fb0527 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
268d3445 1663 // Parse the parameter of source ip address.\r
68fb0527 1664 //\r
0b42d7d8
JW
1665 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
1666 if (ValueStr == NULL) {\r
1667 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s");\r
1668 }\r
ba0014b9 1669\r
68fb0527 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
47d20b54 1675 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS *)&SrcAddress);\r
68fb0527 1676 }\r
47d20b54 1677\r
68fb0527 1678 if (EFI_ERROR (Status)) {\r
ba0014b9 1679 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
68fb0527 1680 ShellStatus = SHELL_INVALID_PARAMETER;\r
1681 goto ON_EXIT;\r
1682 }\r
1683 }\r
47d20b54 1684\r
68fb0527 1685 //\r
268d3445 1686 // Parse the parameter of destination ip address.\r
68fb0527 1687 //\r
47d20b54 1688 NonOptionCount = ShellCommandLineGetCount (ParamPackage);\r
68fb0527 1689 if (NonOptionCount < 2) {\r
ba0014b9 1690 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping");\r
68fb0527 1691 ShellStatus = SHELL_INVALID_PARAMETER;\r
1692 goto ON_EXIT;\r
1693 }\r
47d20b54 1694\r
68fb0527 1695 if (NonOptionCount > 2) {\r
ba0014b9 1696 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping");\r
68fb0527 1697 ShellStatus = SHELL_INVALID_PARAMETER;\r
1698 goto ON_EXIT;\r
1699 }\r
47d20b54 1700\r
68fb0527 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
47d20b54 1707 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS *)&DstAddress);\r
68fb0527 1708 }\r
47d20b54 1709\r
68fb0527 1710 if (EFI_ERROR (Status)) {\r
ba0014b9 1711 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);\r
68fb0527 1712 ShellStatus = SHELL_INVALID_PARAMETER;\r
1713 goto ON_EXIT;\r
1714 }\r
1715 }\r
68fb0527 1716\r
68fb0527 1717 //\r
1718 // Enter into ping process.\r
1719 //\r
1720 ShellStatus = ShellPing (\r
47d20b54
MK
1721 (UINT32)SendNumber,\r
1722 (UINT32)BufferSize,\r
1723 &SrcAddress,\r
1724 &DstAddress,\r
1725 IpChoice\r
1726 );\r
68fb0527 1727\r
1728ON_EXIT:\r
1729 ShellCommandLineFreeVarList (ParamPackage);\r
1730 return ShellStatus;\r
1731}\r