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