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