]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
ShellPkg/Dp: Add null pointer check
[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
787 Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);\r
788\r
789 if (EFI_ERROR (Status)) {\r
790 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
791 return Status;\r
792 }\r
793\r
794 InsertTailList (&Private->TxList, &TxInfo->Link);\r
795 Private->TxCount++;\r
796\r
797 return EFI_SUCCESS;\r
798}\r
799\r
800/**\r
801 Place a completion token into the receive packet queue to receive the echo reply.\r
802\r
803 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
804\r
805 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
806 @retval others Put the token into the receive packet queue unsuccessfully.\r
807\r
808**/\r
809EFI_STATUS\r
68fb0527 810Ping6ReceiveEchoReply (\r
811 IN PING_PRIVATE_DATA *Private\r
812 )\r
813{\r
814 EFI_STATUS Status;\r
815\r
816 ZeroMem (&Private->RxToken, sizeof (PING_IPX_COMPLETION_TOKEN));\r
817\r
818 Status = gBS->CreateEvent (\r
819 EVT_NOTIFY_SIGNAL,\r
820 TPL_CALLBACK,\r
821 Ping6OnEchoReplyReceived,\r
822 Private,\r
823 &Private->RxToken.Event\r
824 );\r
825\r
826 if (EFI_ERROR (Status)) {\r
827 return Status;\r
828 }\r
829\r
830 Private->RxToken.Status = EFI_NOT_READY;\r
831\r
5d8aa7eb
FS
832 Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);\r
833 if (EFI_ERROR (Status)) {\r
834 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);\r
835 }\r
836 return Status;\r
68fb0527 837}\r
838\r
839/**\r
840 Remove the timeout request from the list.\r
841\r
842 @param[in] Event A EFI_EVENT type event.\r
843 @param[in] Context The pointer to Context.\r
844\r
845**/\r
846VOID\r
847EFIAPI\r
848Ping6OnTimerRoutine (\r
849 IN EFI_EVENT Event,\r
850 IN VOID *Context\r
851 )\r
852{\r
853 EFI_STATUS Status;\r
854 PING_PRIVATE_DATA *Private;\r
855 PING_ICMPX_TX_INFO *TxInfo;\r
856 LIST_ENTRY *Entry;\r
857 LIST_ENTRY *NextEntry;\r
858 UINT64 Time;\r
859\r
860 Private = (PING_PRIVATE_DATA *) Context;\r
861 if (Private->Signature != PING_PRIVATE_DATA_SIGNATURE) {\r
862 Private->Status = EFI_NOT_FOUND;\r
863 return;\r
864 }\r
865\r
866 //\r
867 // Retransmit icmp6 echo request packets per second in sendnumber times.\r
868 //\r
869 if (Private->TxCount < Private->SendNum) {\r
870\r
871 Status = PingSendEchoRequest (Private);\r
872 if (Private->TxCount != 0){\r
873 if (EFI_ERROR (Status)) {\r
874 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_SEND_REQUEST), gShellNetwork1HiiHandle, Private->TxCount + 1);\r
875 }\r
876 }\r
877 }\r
878 //\r
879 // Check whether any icmp6 echo request in the list timeout.\r
880 //\r
881 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
882 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
2a326330 883 Time = CalculateTick (Private, TxInfo->TimeStamp, ReadTime (Private));\r
68fb0527 884\r
885 //\r
886 // Remove the timeout echo request from txlist.\r
887 //\r
888 if (Time > DEFAULT_TIMEOUT) {\r
889\r
890 if (EFI_ERROR (TxInfo->Token->Status)) {\r
891 Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
892 }\r
893 //\r
894 // Remove the timeout icmp6 echo request from list.\r
895 //\r
896 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_TIMEOUT), gShellNetwork1HiiHandle, TxInfo->SequenceNum);\r
897\r
898 RemoveEntryList (&TxInfo->Link);\r
899 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
900\r
80f7a8f5
SSESPS
901 Private->RxCount++;\r
902 Private->FailedCount++;\r
903\r
68fb0527 904 if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
905 //\r
906 // All the left icmp6 echo request in the list timeout.\r
907 //\r
908 Private->Status = EFI_TIMEOUT;\r
909 }\r
910 }\r
911 }\r
912}\r
913\r
914/**\r
915 Determine if a IP4 address is Link Local.\r
916\r
917 169.254.1.0 through 169.254.254.255 is link local.\r
918\r
919 @param[in] Address The address to test.\r
920\r
921 @retval TRUE It is.\r
922 @retval FALSE It is not.\r
923**/\r
924BOOLEAN\r
68fb0527 925PingNetIp4IsLinkLocalAddr (\r
926 IN CONST EFI_IPv4_ADDRESS *Address\r
927 )\r
928{\r
929 return ((BOOLEAN)(Address->Addr[0] == 169 && Address->Addr[1] == 254 && Address->Addr[2] >= 1 && Address->Addr[2] <= 254));\r
930}\r
931\r
932/**\r
933 Determine if a IP4 address is unspecified.\r
934\r
935 @param[in] Address The address to test.\r
936\r
937 @retval TRUE It is.\r
938 @retval FALSE It is not.\r
939**/\r
940BOOLEAN\r
68fb0527 941PingNetIp4IsUnspecifiedAddr (\r
942 IN CONST EFI_IPv4_ADDRESS *Address\r
943 )\r
944{\r
945 return ((BOOLEAN)((ReadUnaligned32 ((UINT32*)&Address->Addr[0])) == 0x00000000));\r
946}\r
947\r
948/**\r
949 Create a valid IP instance.\r
950\r
951 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
952\r
953 @retval EFI_SUCCESS Create a valid IPx instance successfully.\r
954 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.\r
955 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.\r
956 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
957 @retval EFI_NOT_FOUND The source address is not found.\r
958**/\r
959EFI_STATUS\r
68fb0527 960PingCreateIpInstance (\r
961 IN PING_PRIVATE_DATA *Private\r
962 )\r
963{\r
964 EFI_STATUS Status;\r
965 UINTN HandleIndex;\r
966 UINTN HandleNum;\r
967 EFI_HANDLE *HandleBuffer;\r
9ce14ca1 968 BOOLEAN UnspecifiedSrc;\r
0f1e07ee 969 EFI_STATUS MediaStatus;\r
68fb0527 970 EFI_SERVICE_BINDING_PROTOCOL *EfiSb;\r
971 VOID *IpXCfg;\r
972 EFI_IP6_CONFIG_DATA Ip6Config;\r
973 EFI_IP4_CONFIG_DATA Ip4Config;\r
974 VOID *IpXInterfaceInfo;\r
975 UINTN IfInfoSize;\r
976 EFI_IPv6_ADDRESS *Addr;\r
977 UINTN AddrIndex;\r
978\r
979 HandleBuffer = NULL;\r
9ce14ca1 980 UnspecifiedSrc = FALSE;\r
0f1e07ee 981 MediaStatus = EFI_SUCCESS;\r
68fb0527 982 EfiSb = NULL;\r
983 IpXInterfaceInfo = NULL;\r
984 IfInfoSize = 0;\r
985\r
986 //\r
987 // Locate all the handles with ip6 service binding protocol.\r
988 //\r
989 Status = gBS->LocateHandleBuffer (\r
990 ByProtocol,\r
991 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
992 NULL,\r
993 &HandleNum,\r
994 &HandleBuffer\r
995 );\r
33c031ee 996 if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) {\r
68fb0527 997 return EFI_ABORTED;\r
998 }\r
9ce14ca1
JW
999\r
1000 if (Private->IpChoice == PING_IP_CHOICE_IP6 ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress) : \\r
1001 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress)) {\r
1002 //\r
1003 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected. \r
1004 //\r
1005 UnspecifiedSrc = TRUE;\r
1006 }\r
1007 \r
68fb0527 1008 //\r
9ce14ca1 1009 // Source address is required when pinging a link-local address.\r
68fb0527 1010 //\r
1011 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
9ce14ca1
JW
1012 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS*)&Private->DstAddress) && UnspecifiedSrc) {\r
1013 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);\r
68fb0527 1014 Status = EFI_INVALID_PARAMETER;\r
1015 goto ON_ERROR;\r
1016 }\r
1017 } else {\r
1018 ASSERT(Private->IpChoice == PING_IP_CHOICE_IP4);\r
9ce14ca1
JW
1019 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS*)&Private->DstAddress) && UnspecifiedSrc) {\r
1020 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle); \r
68fb0527 1021 Status = EFI_INVALID_PARAMETER;\r
1022 goto ON_ERROR;\r
1023 }\r
1024 }\r
9ce14ca1 1025 \r
68fb0527 1026 //\r
1027 // For each ip6 protocol, check interface addresses list.\r
1028 //\r
1029 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
68fb0527 1030 EfiSb = NULL;\r
1031 IpXInterfaceInfo = NULL;\r
1032 IfInfoSize = 0;\r
1033\r
9ce14ca1
JW
1034 if (UnspecifiedSrc) {\r
1035 //\r
1036 // Check media.\r
1037 //\r
0f1e07ee 1038 NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);\r
1039 if (MediaStatus != EFI_SUCCESS) {\r
9ce14ca1
JW
1040 //\r
1041 // Skip this one.\r
1042 //\r
1043 continue;\r
1044 }\r
1045 }\r
1046\r
68fb0527 1047 Status = gBS->HandleProtocol (\r
1048 HandleBuffer[HandleIndex],\r
1049 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
1050 (VOID **) &EfiSb\r
1051 );\r
1052 if (EFI_ERROR (Status)) {\r
1053 goto ON_ERROR;\r
1054 }\r
1055\r
9ce14ca1
JW
1056 //\r
1057 // Ip6config protocol and ip6 service binding protocol are installed\r
1058 // on the same handle.\r
1059 //\r
1060 Status = gBS->HandleProtocol (\r
1061 HandleBuffer[HandleIndex],\r
1062 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ConfigProtocolGuid:&gEfiIp4Config2ProtocolGuid,\r
1063 (VOID **) &IpXCfg\r
1064 );\r
68fb0527 1065\r
9ce14ca1
JW
1066 if (EFI_ERROR (Status)) {\r
1067 goto ON_ERROR;\r
1068 }\r
1069 //\r
1070 // Get the interface information size.\r
1071 //\r
1072 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1073 Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
1074 IpXCfg,\r
1075 Ip6ConfigDataTypeInterfaceInfo,\r
1076 &IfInfoSize,\r
1077 NULL\r
1078 );\r
1079 } else {\r
1080 Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData (\r
1081 IpXCfg,\r
1082 Ip4Config2DataTypeInterfaceInfo,\r
1083 &IfInfoSize,\r
1084 NULL\r
1085 );\r
1086 }\r
1087 \r
1088 //\r
1089 // Skip the ones not in current use.\r
1090 //\r
1091 if (Status == EFI_NOT_STARTED) {\r
1092 continue;\r
1093 }\r
68fb0527 1094\r
9ce14ca1
JW
1095 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1096 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
1097 goto ON_ERROR;\r
1098 }\r
68fb0527 1099\r
9ce14ca1 1100 IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
68fb0527 1101\r
9ce14ca1
JW
1102 if (IpXInterfaceInfo == NULL) {\r
1103 Status = EFI_OUT_OF_RESOURCES;\r
1104 goto ON_ERROR;\r
1105 }\r
1106 //\r
1107 // Get the interface info.\r
1108 //\r
1109 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1110 Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
1111 IpXCfg,\r
1112 Ip6ConfigDataTypeInterfaceInfo,\r
1113 &IfInfoSize,\r
1114 IpXInterfaceInfo\r
1115 );\r
1116 } else {\r
1117 Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData (\r
1118 IpXCfg,\r
1119 Ip4Config2DataTypeInterfaceInfo,\r
1120 &IfInfoSize,\r
1121 IpXInterfaceInfo\r
1122 );\r
1123 }\r
68fb0527 1124\r
9ce14ca1
JW
1125 if (EFI_ERROR (Status)) {\r
1126 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
1127 goto ON_ERROR;\r
1128 }\r
1129 //\r
1130 // Check whether the source address is one of the interface addresses.\r
1131 //\r
1132 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1133 for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) {\r
1134 Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address);\r
68fb0527 1135\r
9ce14ca1
JW
1136 if (UnspecifiedSrc) {\r
1137 if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {\r
68fb0527 1138 //\r
9ce14ca1 1139 // Select the interface automatically.\r
68fb0527 1140 //\r
9ce14ca1 1141 CopyMem(&Private->SrcAddress, Addr, sizeof(Private->SrcAddress));\r
68fb0527 1142 break;\r
1143 }\r
9ce14ca1 1144 } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
68fb0527 1145 //\r
9ce14ca1 1146 // Match a certain interface address.\r
68fb0527 1147 //\r
1148 break;\r
1149 }\r
9ce14ca1
JW
1150 }\r
1151\r
1152 if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) {\r
68fb0527 1153 //\r
9ce14ca1 1154 // Found a nic handle with right interface address.\r
68fb0527 1155 //\r
9ce14ca1
JW
1156 break;\r
1157 }\r
1158 } else {\r
1159 if (UnspecifiedSrc) {\r
1160 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress) && \r
1161 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress)) {\r
68fb0527 1162 //\r
9ce14ca1 1163 // Select the interface automatically.\r
68fb0527 1164 //\r
1165 break;\r
1166 }\r
9ce14ca1
JW
1167 } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress)) {\r
1168 //\r
1169 // Match a certain interface address.\r
1170 //\r
1171 break;\r
68fb0527 1172 }\r
1173 }\r
1174\r
1175 FreePool (IpXInterfaceInfo);\r
1176 IpXInterfaceInfo = NULL;\r
1177 }\r
1178 //\r
1179 // No exact interface address matched.\r
1180 //\r
1181\r
1182 if (HandleIndex == HandleNum) {\r
ab7c10f2 1183 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping"); \r
68fb0527 1184 Status = EFI_NOT_FOUND;\r
1185 goto ON_ERROR;\r
1186 }\r
1187\r
1188 Private->NicHandle = HandleBuffer[HandleIndex];\r
1189\r
1190 ASSERT (EfiSb != NULL);\r
1191 Status = EfiSb->CreateChild (EfiSb, &Private->IpChildHandle);\r
1192\r
1193 if (EFI_ERROR (Status)) {\r
1194 goto ON_ERROR;\r
1195 }\r
1196 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1197 Status = gBS->OpenProtocol (\r
1198 Private->IpChildHandle,\r
1199 &gEfiIp6ProtocolGuid,\r
1200 &Private->IpProtocol,\r
1201 gImageHandle,\r
1202 Private->IpChildHandle,\r
1203 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1204 );\r
1205 if (EFI_ERROR (Status)) {\r
1206 goto ON_ERROR;\r
1207 }\r
1208\r
1209\r
1210 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
1211\r
1212 //\r
1213 // Configure the ip6 instance for icmp6 packet exchange.\r
1214 //\r
1215 Ip6Config.DefaultProtocol = 58;\r
1216 Ip6Config.AcceptAnyProtocol = FALSE;\r
1217 Ip6Config.AcceptIcmpErrors = TRUE;\r
1218 Ip6Config.AcceptPromiscuous = FALSE;\r
1219 Ip6Config.TrafficClass = 0;\r
1220 Ip6Config.HopLimit = 128;\r
1221 Ip6Config.FlowLabel = 0;\r
1222 Ip6Config.ReceiveTimeout = 0;\r
1223 Ip6Config.TransmitTimeout = 0;\r
1224\r
1225 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
1226 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
1227\r
1228 Status = ((EFI_IP6_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config);\r
1229\r
1230 if (EFI_ERROR (Status)) {\r
1231 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
1232 goto ON_ERROR;\r
1233 }\r
1234\r
1235 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Transmit;\r
1236 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Receive;\r
1237 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Cancel;\r
1238 Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Poll;\r
1239 } else {\r
1240 Status = gBS->OpenProtocol (\r
1241 Private->IpChildHandle,\r
1242 &gEfiIp4ProtocolGuid,\r
1243 &Private->IpProtocol,\r
1244 gImageHandle,\r
1245 Private->IpChildHandle,\r
1246 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1247 );\r
1248 if (EFI_ERROR (Status)) {\r
1249 goto ON_ERROR;\r
1250 }\r
1251\r
1252\r
1253 ZeroMem (&Ip4Config, sizeof (EFI_IP4_CONFIG_DATA));\r
1254\r
1255 //\r
1256 // Configure the ip4 instance for icmp4 packet exchange.\r
1257 //\r
68fb0527 1258 Ip4Config.DefaultProtocol = 1;\r
1259 Ip4Config.AcceptAnyProtocol = FALSE;\r
1260 Ip4Config.AcceptBroadcast = FALSE;\r
1261 Ip4Config.AcceptIcmpErrors = TRUE;\r
1262 Ip4Config.AcceptPromiscuous = FALSE;\r
1263 Ip4Config.DoNotFragment = FALSE;\r
1264 Ip4Config.RawData = FALSE;\r
1265 Ip4Config.ReceiveTimeout = 0;\r
1266 Ip4Config.TransmitTimeout = 0;\r
1267 Ip4Config.UseDefaultAddress = TRUE;\r
1268 Ip4Config.TimeToLive = 128;\r
1269 Ip4Config.TypeOfService = 0;\r
1270\r
1271 Status = ((EFI_IP4_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config);\r
1272\r
1273 if (EFI_ERROR (Status)) {\r
1274 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
1275 goto ON_ERROR;\r
1276 }\r
1277\r
1278 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Transmit;\r
1279 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Receive;\r
1280 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Cancel;\r
1281 Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Poll; \r
1282 }\r
1283\r
1284 if (HandleBuffer != NULL) {\r
1285 FreePool (HandleBuffer);\r
1286 }\r
1287\r
1288 return EFI_SUCCESS;\r
1289\r
1290ON_ERROR:\r
1291 if (HandleBuffer != NULL) {\r
1292 FreePool (HandleBuffer);\r
1293 }\r
1294\r
1295 if (IpXInterfaceInfo != NULL) {\r
1296 FreePool (IpXInterfaceInfo);\r
1297 }\r
1298\r
1299 if ((EfiSb != NULL) && (Private->IpChildHandle != NULL)) {\r
1300 EfiSb->DestroyChild (EfiSb, Private->IpChildHandle);\r
1301 }\r
1302\r
1303 return Status;\r
1304}\r
1305\r
1306/**\r
75dce340 1307 Destroy the IP instance.\r
68fb0527 1308\r
1309 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
1310\r
1311**/\r
1312VOID\r
75dce340 1313Ping6DestroyIp6Instance (\r
68fb0527 1314 IN PING_PRIVATE_DATA *Private\r
1315 )\r
1316{\r
1317 EFI_STATUS Status;\r
1318 EFI_SERVICE_BINDING_PROTOCOL *IpSb;\r
1319\r
1320 gBS->CloseProtocol (\r
1321 Private->IpChildHandle,\r
1322 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ProtocolGuid:&gEfiIp4ProtocolGuid,\r
1323 gImageHandle,\r
1324 Private->IpChildHandle\r
1325 );\r
1326\r
1327 Status = gBS->HandleProtocol (\r
1328 Private->NicHandle,\r
1329 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
1330 (VOID **) &IpSb\r
1331 );\r
1332\r
1333 if (!EFI_ERROR(Status)) {\r
1334 IpSb->DestroyChild (IpSb, Private->IpChildHandle);\r
1335 }\r
1336}\r
1337\r
2a326330 1338\r
68fb0527 1339/**\r
1340 The Ping Process.\r
1341\r
1342 @param[in] SendNumber The send request count.\r
1343 @param[in] BufferSize The send buffer size.\r
1344 @param[in] SrcAddress The source address.\r
1345 @param[in] DstAddress The destination address.\r
1346 @param[in] IpChoice The choice between IPv4 and IPv6.\r
1347\r
1348 @retval SHELL_SUCCESS The ping processed successfullly.\r
1349 @retval others The ping processed unsuccessfully.\r
1350**/\r
1351SHELL_STATUS\r
68fb0527 1352ShellPing (\r
1353 IN UINT32 SendNumber,\r
1354 IN UINT32 BufferSize,\r
1355 IN EFI_IPv6_ADDRESS *SrcAddress,\r
1356 IN EFI_IPv6_ADDRESS *DstAddress,\r
1357 IN UINT32 IpChoice\r
1358 )\r
1359{\r
1360 EFI_STATUS Status;\r
1361 PING_PRIVATE_DATA *Private;\r
1362 PING_ICMPX_TX_INFO *TxInfo;\r
1363 LIST_ENTRY *Entry;\r
1364 LIST_ENTRY *NextEntry;\r
1365 SHELL_STATUS ShellStatus;\r
1366\r
1367 ShellStatus = SHELL_SUCCESS;\r
1368 Private = AllocateZeroPool (sizeof (PING_PRIVATE_DATA));\r
1369\r
1370 if (Private == NULL) {\r
1371 return (SHELL_OUT_OF_RESOURCES);\r
1372 }\r
1373\r
1374 Private->IpChoice = IpChoice;\r
1375 Private->Signature = PING_PRIVATE_DATA_SIGNATURE;\r
1376 Private->SendNum = SendNumber;\r
1377 Private->BufferSize = BufferSize;\r
1378 Private->RttMin = ~((UINT64 )(0x0));\r
1379 Private->Status = EFI_NOT_READY;\r
1380\r
1381 CopyMem(&Private->SrcAddress, SrcAddress, sizeof(Private->SrcAddress));\r
1382 CopyMem(&Private->DstAddress, DstAddress, sizeof(Private->DstAddress));\r
1383\r
1384 InitializeListHead (&Private->TxList);\r
1385\r
1386 //\r
1387 // Open and configure a ip instance for us.\r
1388 //\r
1389 Status = PingCreateIpInstance (Private);\r
1390\r
1391 if (EFI_ERROR (Status)) {\r
1392 ShellStatus = SHELL_ACCESS_DENIED;\r
1393 goto ON_EXIT;\r
1394 }\r
1395 //\r
1396 // Print the command line itself.\r
1397 //\r
1398 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_START), gShellNetwork1HiiHandle, mDstString, Private->BufferSize);\r
1399 //\r
1400 // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
1401 //\r
1402 Status = Ping6ReceiveEchoReply (Private);\r
1403\r
1404 if (EFI_ERROR (Status)) {\r
1405 ShellStatus = SHELL_ACCESS_DENIED;\r
1406 goto ON_EXIT;\r
1407 }\r
1408 //\r
1409 // Create and start timer to send icmp6 echo request packet per second.\r
1410 //\r
1411 Status = gBS->CreateEvent (\r
1412 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1413 TPL_CALLBACK,\r
1414 Ping6OnTimerRoutine,\r
1415 Private,\r
1416 &Private->Timer\r
1417 );\r
1418\r
1419 if (EFI_ERROR (Status)) {\r
1420 ShellStatus = SHELL_ACCESS_DENIED;\r
1421 goto ON_EXIT;\r
1422 }\r
2a326330
FS
1423\r
1424 //\r
1425 // Start a timer to calculate the RTT.\r
1426 //\r
1427 Status = PingInitRttTimer (Private);\r
1428 if (EFI_ERROR (Status)) {\r
1429 ShellStatus = SHELL_ACCESS_DENIED;\r
1430 goto ON_EXIT;\r
1431 }\r
1432 \r
68fb0527 1433 //\r
1434 // Create a ipv6 token to send the first icmp6 echo request packet.\r
1435 //\r
1436 Status = PingSendEchoRequest (Private);\r
1437 //\r
1438 // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
1439 //\r
1440 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
1441 ShellStatus = SHELL_ACCESS_DENIED;\r
1442 if(Status == EFI_NOT_FOUND) {\r
1443 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOSOURCE_INDO), gShellNetwork1HiiHandle, mDstString);\r
1444 } else if (Status == RETURN_NO_MAPPING) {\r
1445 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString);\r
1446 } else {\r
ab7c10f2 1447 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, L"ping", Status); \r
68fb0527 1448 }\r
1449\r
1450 goto ON_EXIT;\r
1451 }\r
1452\r
1453 Status = gBS->SetTimer (\r
1454 Private->Timer,\r
1455 TimerPeriodic,\r
1456 ONE_SECOND\r
1457 );\r
1458\r
1459 if (EFI_ERROR (Status)) {\r
1460 ShellStatus = SHELL_ACCESS_DENIED;\r
1461 goto ON_EXIT;\r
1462 }\r
1463 //\r
1464 // Control the ping6 process by two factors:\r
1465 // 1. Hot key\r
1466 // 2. Private->Status\r
1467 // 2.1. success means all icmp6 echo request packets get reply packets.\r
1468 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
1469 // 2.3. noready means ping6 process is on-the-go.\r
1470 //\r
1471 while (Private->Status == EFI_NOT_READY) {\r
1472 Status = Private->ProtocolPointers.Poll (Private->IpProtocol);\r
1473 if (ShellGetExecutionBreakFlag()) {\r
1474 Private->Status = EFI_ABORTED;\r
1475 goto ON_STAT;\r
1476 }\r
1477 }\r
1478\r
1479ON_STAT:\r
1480 //\r
1481 // Display the statistics in all.\r
1482 //\r
1483 gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
1484\r
1485 if (Private->TxCount != 0) {\r
1486 ShellPrintHiiEx (\r
1487 -1,\r
1488 -1,\r
1489 NULL,\r
1490 STRING_TOKEN (STR_PING_STAT),\r
1491 gShellNetwork1HiiHandle,\r
1492 Private->TxCount,\r
80f7a8f5
SSESPS
1493 (Private->RxCount - Private->FailedCount),\r
1494 (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)),\r
68fb0527 1495 Private->RttSum\r
1496 );\r
1497 }\r
1498\r
80f7a8f5 1499 if (Private->RxCount > Private->FailedCount) {\r
68fb0527 1500 ShellPrintHiiEx (\r
1501 -1,\r
1502 -1,\r
1503 NULL,\r
1504 STRING_TOKEN (STR_PING_RTT),\r
1505 gShellNetwork1HiiHandle,\r
1506 Private->RttMin,\r
2a326330 1507 Private->RttMin + Private->TimerPeriod,\r
68fb0527 1508 Private->RttMax,\r
2a326330
FS
1509 Private->RttMax + Private->TimerPeriod,\r
1510 DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL),\r
1511 DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod\r
68fb0527 1512 );\r
1513 }\r
1514\r
1515ON_EXIT:\r
1516\r
1517 if (Private != NULL) {\r
1518\r
1519 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
1520 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
1521\r
1522 if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) {\r
1523 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
1524 }\r
1525\r
1526 RemoveEntryList (&TxInfo->Link);\r
1527 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
1528 }\r
1529\r
2a326330
FS
1530 PingFreeRttTimer (Private);\r
1531\r
68fb0527 1532 if (Private->Timer != NULL) {\r
1533 gBS->CloseEvent (Private->Timer);\r
1534 }\r
1535\r
1536 if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) {\r
1537 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, &Private->RxToken);\r
1538 }\r
1539\r
1540 if (Private->RxToken.Event != NULL) {\r
1541 gBS->CloseEvent (Private->RxToken.Event);\r
1542 }\r
1543\r
1544 if (Private->IpChildHandle != NULL) {\r
75dce340 1545 Ping6DestroyIp6Instance (Private);\r
68fb0527 1546 }\r
1547\r
1548 FreePool (Private);\r
1549 }\r
1550\r
1551 return ShellStatus;\r
1552}\r
1553\r
1554/**\r
1555 Function for 'ping' command.\r
1556\r
1557 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
1558 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
7c25b7ea 1559\r
1560 @retval SHELL_SUCCESS The ping processed successfullly.\r
1561 @retval others The ping processed unsuccessfully.\r
1562 \r
68fb0527 1563**/\r
1564SHELL_STATUS\r
1565EFIAPI\r
1566ShellCommandRunPing (\r
1567 IN EFI_HANDLE ImageHandle,\r
1568 IN EFI_SYSTEM_TABLE *SystemTable\r
1569 )\r
1570{\r
1571 EFI_STATUS Status;\r
1572 SHELL_STATUS ShellStatus;\r
1573 EFI_IPv6_ADDRESS DstAddress;\r
1574 EFI_IPv6_ADDRESS SrcAddress;\r
1575 UINT64 BufferSize;\r
1576 UINTN SendNumber;\r
1577 LIST_ENTRY *ParamPackage;\r
1578 CONST CHAR16 *ValueStr;\r
1579 UINTN NonOptionCount;\r
1580 UINT32 IpChoice;\r
ab7c10f2 1581 CHAR16 *ProblemParam;\r
68fb0527 1582\r
1583 //\r
1584 // we use IPv6 buffers to hold items... \r
1585 // make sure this is enough space!\r
1586 //\r
1587 ASSERT(sizeof(EFI_IPv4_ADDRESS ) <= sizeof(EFI_IPv6_ADDRESS ));\r
1588 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN) <= sizeof(EFI_IP6_COMPLETION_TOKEN ));\r
1589\r
1590 IpChoice = PING_IP_CHOICE_IP4;\r
1591\r
1592 ShellStatus = SHELL_SUCCESS;\r
ab7c10f2 1593 ProblemParam = NULL;\r
68fb0527 1594\r
ab7c10f2 1595 Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);\r
68fb0527 1596 if (EFI_ERROR(Status)) {\r
ab7c10f2 1597 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);\r
68fb0527 1598 ShellStatus = SHELL_INVALID_PARAMETER;\r
1599 goto ON_EXIT;\r
1600 }\r
1601\r
1602 if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) {\r
1603 IpChoice = PING_IP_CHOICE_IP6;\r
1604 }\r
1605\r
1606 //\r
268d3445 1607 // Parse the parameter of count number.\r
68fb0527 1608 //\r
1609 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
1610 if (ValueStr != NULL) {\r
1611 SendNumber = ShellStrToUintn (ValueStr);\r
1612\r
1613 //\r
1614 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1615 //\r
1616 if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) {\r
ab7c10f2 1617 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); \r
68fb0527 1618 ShellStatus = SHELL_INVALID_PARAMETER;\r
1619 goto ON_EXIT;\r
1620 }\r
1621 } else {\r
1622 SendNumber = DEFAULT_SEND_COUNT;\r
1623 }\r
1624 //\r
268d3445 1625 // Parse the parameter of buffer size.\r
68fb0527 1626 //\r
1627 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
1628 if (ValueStr != NULL) {\r
1629 BufferSize = ShellStrToUintn (ValueStr);\r
1630\r
1631 //\r
1632 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1633 //\r
1634 if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) {\r
ab7c10f2 1635 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); \r
68fb0527 1636 ShellStatus = SHELL_INVALID_PARAMETER;\r
1637 goto ON_EXIT;\r
1638 }\r
1639 } else {\r
1640 BufferSize = DEFAULT_BUFFER_SIZE;\r
1641 }\r
1642\r
1643 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
1644 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
1645\r
1646 //\r
268d3445 1647 // Parse the parameter of source ip address.\r
68fb0527 1648 //\r
0b42d7d8
JW
1649 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
1650 if (ValueStr == NULL) {\r
1651 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s");\r
1652 }\r
1653 \r
68fb0527 1654 if (ValueStr != NULL) {\r
1655 mSrcString = ValueStr;\r
1656 if (IpChoice == PING_IP_CHOICE_IP6) {\r
1657 Status = NetLibStrToIp6 (ValueStr, &SrcAddress);\r
1658 } else {\r
1659 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&SrcAddress);\r
1660 }\r
1661 if (EFI_ERROR (Status)) {\r
ab7c10f2 1662 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); \r
68fb0527 1663 ShellStatus = SHELL_INVALID_PARAMETER;\r
1664 goto ON_EXIT;\r
1665 }\r
1666 }\r
1667 //\r
268d3445 1668 // Parse the parameter of destination ip address.\r
68fb0527 1669 //\r
1670 NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
1671 if (NonOptionCount < 2) {\r
ab7c10f2 1672 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping"); \r
68fb0527 1673 ShellStatus = SHELL_INVALID_PARAMETER;\r
1674 goto ON_EXIT;\r
1675 }\r
1676 if (NonOptionCount > 2) {\r
ab7c10f2 1677 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping"); \r
68fb0527 1678 ShellStatus = SHELL_INVALID_PARAMETER;\r
1679 goto ON_EXIT;\r
1680 }\r
1681 ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);\r
1682 if (ValueStr != NULL) {\r
1683 mDstString = ValueStr;\r
1684 if (IpChoice == PING_IP_CHOICE_IP6) {\r
1685 Status = NetLibStrToIp6 (ValueStr, &DstAddress);\r
1686 } else {\r
1687 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&DstAddress);\r
1688 }\r
1689 if (EFI_ERROR (Status)) {\r
ab7c10f2 1690 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); \r
68fb0527 1691 ShellStatus = SHELL_INVALID_PARAMETER;\r
1692 goto ON_EXIT;\r
1693 }\r
1694 }\r
68fb0527 1695\r
68fb0527 1696 //\r
1697 // Enter into ping process.\r
1698 //\r
1699 ShellStatus = ShellPing (\r
1700 (UINT32)SendNumber,\r
1701 (UINT32)BufferSize,\r
1702 &SrcAddress,\r
1703 &DstAddress,\r
1704 IpChoice\r
1705 );\r
1706\r
1707ON_EXIT:\r
1708 ShellCommandLineFreeVarList (ParamPackage);\r
1709 return ShellStatus;\r
1710}\r