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