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