TianoCore EDK2 master
Loading...
Searching...
No Matches
Ping.c
Go to the documentation of this file.
1
13
14#define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
15
16UINT64 mCurrentTick = 0;
17
18//
19// Function templates to match the IPv4 and IPv6 commands that we use.
20//
21typedef
23(EFIAPI *PING_IPX_POLL)(
24 IN VOID *This
25 );
26
27typedef
29(EFIAPI *PING_IPX_TRANSMIT)(
30 IN VOID *This,
31 IN VOID *Token
32 );
33
34typedef
36(EFIAPI *PING_IPX_RECEIVE)(
37 IN VOID *This,
38 IN VOID *Token
39 );
40
41typedef
43(EFIAPI *PING_IPX_CANCEL)(
44 IN VOID *This,
45 IN VOID *Token OPTIONAL
46 );
47
52typedef struct {
53 PING_IPX_TRANSMIT Transmit;
54 PING_IPX_RECEIVE Receive;
55 PING_IPX_CANCEL Cancel;
56 PING_IPX_POLL Poll;
58
59typedef union {
60 VOID *RxData;
61 VOID *TxData;
63
64//
65// PING_IPX_COMPLETION_TOKEN
66// structures are used for both transmit and receive operations.
67// This version is IP-unaware.
68//
69typedef struct {
70 EFI_EVENT Event;
71 EFI_STATUS Status;
72 PING_PACKET Packet;
74
75#pragma pack(1)
77 UINT8 Type;
78 UINT8 Code;
79 UINT16 Checksum;
80 UINT16 Identifier;
81 UINT16 SequenceNum;
82 UINT32 TimeStamp;
83 UINT8 Data[1];
85#pragma pack()
86
87typedef struct _PING_ICMP_TX_INFO {
88 LIST_ENTRY Link;
89 UINT16 SequenceNum;
90 UINT32 TimeStamp;
93
94#define DEFAULT_TIMEOUT 5000
95#define MAX_SEND_NUMBER 10000
96#define MAX_BUFFER_SIZE 32768
97#define DEFAULT_TIMER_PERIOD 358049
98#define ONE_SECOND 10000000
99#define PING_IP_CHOICE_IP4 1
100#define PING_IP_CHOICE_IP6 2
101#define DEFAULT_SEND_COUNT 10
102#define DEFAULT_BUFFER_SIZE 16
103#define ICMP_V4_ECHO_REQUEST 0x8
104#define ICMP_V4_ECHO_REPLY 0x0
105#define STALL_1_MILLI_SECOND 1000
106
107#define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
108typedef struct _PING_PRIVATE_DATA {
109 UINT32 Signature;
110 EFI_HANDLE NicHandle;
111 EFI_HANDLE IpChildHandle;
112 EFI_EVENT Timer;
113
114 UINT32 TimerPeriod;
115 UINT32 RttTimerTick;
116 EFI_EVENT RttTimer;
117
118 EFI_STATUS Status;
119 LIST_ENTRY TxList;
120 UINT16 RxCount;
121 UINT16 TxCount;
122 UINT64 RttSum;
123 UINT64 RttMin;
124 UINT64 RttMax;
125 UINT32 SequenceNum;
126
127 UINT32 SendNum;
128 UINT32 BufferSize;
129 UINT32 IpChoice;
130
131 PING_IPX_PROTOCOL ProtocolPointers;
132 VOID *IpProtocol;
133 UINT8 SrcAddress[MAX (sizeof (EFI_IPv6_ADDRESS), sizeof (EFI_IPv4_ADDRESS))];
134 UINT8 DstAddress[MAX (sizeof (EFI_IPv6_ADDRESS), sizeof (EFI_IPv4_ADDRESS))];
136 UINT16 FailedCount;
138
148UINT16
150 IN UINT8 *Buffer,
151 IN UINT32 Length
152 )
153{
154 UINT32 Sum;
155 UINT8 Odd;
156 UINT16 *Packet;
157
158 Packet = (UINT16 *)Buffer;
159
160 Sum = 0;
161 Odd = (UINT8)(Length & 1);
162 Length >>= 1;
163 while ((Length--) != 0) {
164 Sum += *Packet++;
165 }
166
167 if (Odd != 0) {
168 Sum += *(UINT8 *)Packet;
169 }
170
171 Sum = (Sum & 0xffff) + (Sum >> 16);
172
173 //
174 // in case above carried
175 //
176 Sum += Sum >> 16;
177
178 return (UINT16)Sum;
179}
180
191 {
192 L"-l",
194 },
195 {
196 L"-n",
198 },
199 {
200 L"-s",
202 },
203 {
204 L"-_s",
206 },
207 {
208 L"-_ip6",
210 },
211 {
212 NULL,
213 TypeMax
214 },
215};
216
217//
218// Global Variables in Ping command.
219//
220STATIC CONST CHAR16 *mDstString;
221STATIC CONST CHAR16 *mSrcString;
222
230VOID
231EFIAPI
233 IN EFI_EVENT Event,
234 IN VOID *Context
235 )
236{
237 UINT32 *RttTimerTick;
238
239 RttTimerTick = (UINT32 *)Context;
240 (*RttTimerTick)++;
241}
242
252UINT32
254 VOID
255 )
256{
257 EFI_STATUS Status;
258 UINT32 RttTimerTick;
259 EFI_EVENT TimerEvent;
260 UINT32 StallCounter;
261 EFI_TPL OldTpl;
262 UINT32 TimerPeriod;
263
264 RttTimerTick = 0;
265 StallCounter = 0;
266 TimerPeriod = 0;
267
268 Status = gBS->CreateEvent (
269 EVT_TIMER | EVT_NOTIFY_SIGNAL,
270 TPL_NOTIFY,
272 &RttTimerTick,
273 &TimerEvent
274 );
275 if (EFI_ERROR (Status)) {
276 return 0;
277 }
278
279 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
280 Status = gBS->SetTimer (
281 TimerEvent,
283 TICKS_PER_MS
284 );
285 if (EFI_ERROR (Status)) {
286 gBS->CloseEvent (TimerEvent);
287 return 0;
288 }
289
290 while (RttTimerTick < 10) {
291 gBS->Stall (STALL_1_MILLI_SECOND);
292 ++StallCounter;
293 }
294
295 gBS->RestoreTPL (OldTpl);
296
297 gBS->SetTimer (TimerEvent, TimerCancel, 0);
298 gBS->CloseEvent (TimerEvent);
299
300 TimerPeriod = StallCounter / RttTimerTick;
301 if (TimerPeriod != 0) {
302 return TimerPeriod;
303 } else {
304 return 1;
305 }
306}
307
319 PING_PRIVATE_DATA *Private
320 )
321{
322 EFI_STATUS Status;
323
324 Private->TimerPeriod = GetTimerPeriod ();
325 if (Private->TimerPeriod == 0) {
326 return EFI_ABORTED;
327 }
328
329 Private->RttTimerTick = 0;
330 Status = gBS->CreateEvent (
331 EVT_TIMER | EVT_NOTIFY_SIGNAL,
332 TPL_NOTIFY,
334 &Private->RttTimerTick,
335 &Private->RttTimer
336 );
337 if (EFI_ERROR (Status)) {
338 return Status;
339 }
340
341 Status = gBS->SetTimer (
342 Private->RttTimer,
344 TICKS_PER_MS
345 );
346 if (EFI_ERROR (Status)) {
347 gBS->CloseEvent (Private->RttTimer);
348 return Status;
349 }
350
351 return EFI_SUCCESS;
352}
353
360VOID
362 PING_PRIVATE_DATA *Private
363 )
364{
365 if (Private->RttTimer != NULL) {
366 gBS->SetTimer (Private->RttTimer, TimerCancel, 0);
367 gBS->CloseEvent (Private->RttTimer);
368 }
369}
370
378UINT32
380 PING_PRIVATE_DATA *Private
381 )
382{
383 return Private->RttTimerTick;
384}
385
396UINT32
398 PING_PRIVATE_DATA *Private,
399 IN UINT32 Begin,
400 IN UINT32 End
401 )
402{
403 if (End < Begin) {
404 return (0);
405 }
406
407 return (End - Begin) * Private->TimerPeriod;
408}
409
416VOID
418 IN PING_ICMPX_TX_INFO *TxInfo,
419 IN UINT32 IpChoice
420 )
421{
422 EFI_IP6_TRANSMIT_DATA *Ip6TxData;
423 EFI_IP4_TRANSMIT_DATA *Ip4TxData;
424 EFI_IP6_FRAGMENT_DATA *FragData;
425 UINTN Index;
426
427 if (TxInfo == NULL) {
428 return;
429 }
430
431 if (TxInfo->Token != NULL) {
432 if (TxInfo->Token->Event != NULL) {
433 gBS->CloseEvent (TxInfo->Token->Event);
434 }
435
436 if (TxInfo->Token->Packet.TxData != NULL) {
437 if (IpChoice == PING_IP_CHOICE_IP6) {
438 Ip6TxData = TxInfo->Token->Packet.TxData;
439
440 if (Ip6TxData->OverrideData != NULL) {
441 FreePool (Ip6TxData->OverrideData);
442 }
443
444 if (Ip6TxData->ExtHdrs != NULL) {
445 FreePool (Ip6TxData->ExtHdrs);
446 }
447
448 for (Index = 0; Index < Ip6TxData->FragmentCount; Index++) {
449 FragData = Ip6TxData->FragmentTable[Index].FragmentBuffer;
450 if (FragData != NULL) {
451 FreePool (FragData);
452 }
453 }
454 } else {
455 Ip4TxData = TxInfo->Token->Packet.TxData;
456
457 if (Ip4TxData->OverrideData != NULL) {
458 FreePool (Ip4TxData->OverrideData);
459 }
460
461 for (Index = 0; Index < Ip4TxData->FragmentCount; Index++) {
462 FragData = Ip4TxData->FragmentTable[Index].FragmentBuffer;
463 if (FragData != NULL) {
464 FreePool (FragData);
465 }
466 }
467 }
468 }
469
470 FreePool (TxInfo->Token);
471 }
472
473 FreePool (TxInfo);
474}
475
488 IN PING_PRIVATE_DATA *Private,
490 )
491{
492 PING_ICMPX_TX_INFO *TxInfo;
493 LIST_ENTRY *Entry;
494 LIST_ENTRY *NextEntry;
495
496 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
497 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);
498
499 if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) {
500 Private->RxCount++;
501 RemoveEntryList (&TxInfo->Link);
502 PingDestroyTxInfo (TxInfo, Private->IpChoice);
503 return EFI_SUCCESS;
504 }
505 }
506
507 return EFI_NOT_FOUND;
508}
509
520VOID
521EFIAPI
523 IN EFI_EVENT Event,
524 IN VOID *Context
525 )
526{
527}
528
536VOID
537EFIAPI
539 IN EFI_EVENT Event,
540 IN VOID *Context
541 )
542{
543 EFI_STATUS Status;
544 PING_PRIVATE_DATA *Private;
546 UINT32 PayLoad;
547 UINT32 Rtt;
548
549 Private = (PING_PRIVATE_DATA *)Context;
550
551 if ((Private == NULL) || (Private->Status == EFI_ABORTED) || (Private->Signature != PING_PRIVATE_DATA_SIGNATURE)) {
552 return;
553 }
554
555 if (Private->RxToken.Packet.RxData == NULL) {
556 return;
557 }
558
559 if (Private->IpChoice == PING_IP_CHOICE_IP6) {
560 Reply = ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer;
561 PayLoad = ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->DataLength;
562 if (((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->NextHeader != IP6_ICMP) {
563 goto ON_EXIT;
564 }
565
566 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS *)&Private->DstAddress) &&
567 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv6_ADDRESS *)&Private->DstAddress))
568 {
569 goto ON_EXIT;
570 }
571
572 if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) {
573 goto ON_EXIT;
574 }
575 } else {
576 Reply = ((EFI_IP4_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer;
577 PayLoad = ((EFI_IP4_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->DataLength;
578 if (!IP4_IS_MULTICAST (EFI_IP4 (*(EFI_IPv4_ADDRESS *)Private->DstAddress)) &&
579 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv4_ADDRESS *)&Private->DstAddress))
580 {
581 goto ON_EXIT;
582 }
583
584 if ((Reply->Type != ICMP_V4_ECHO_REPLY) || (Reply->Code != 0)) {
585 goto ON_EXIT;
586 }
587 }
588
589 if (PayLoad != Private->BufferSize) {
590 goto ON_EXIT;
591 }
592
593 //
594 // Check whether the reply matches the sent request before.
595 //
596 Status = Ping6MatchEchoReply (Private, Reply);
597 if (EFI_ERROR (Status)) {
598 goto ON_EXIT;
599 }
600
601 //
602 // Display statistics on this icmp6 echo reply packet.
603 //
604 Rtt = CalculateTick (Private, Reply->TimeStamp, ReadTime (Private));
605
606 Private->RttSum += Rtt;
607 Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;
608 Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax;
609
611 -1,
612 -1,
613 NULL,
614 STRING_TOKEN (STR_PING_REPLY_INFO),
615 gShellNetwork1HiiHandle,
616 PayLoad,
617 mDstString,
618 Reply->SequenceNum,
619 Private->IpChoice == PING_IP_CHOICE_IP6 ? ((EFI_IP6_RECEIVE_DATA *)Private->RxToken.Packet.RxData)->Header->HopLimit : 0,
620 Rtt,
621 Rtt + Private->TimerPeriod
622 );
623
624ON_EXIT:
625
626 //
627 // Recycle the packet before reusing RxToken
628 //
629 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);
630
631 if (Private->RxCount < Private->SendNum) {
632 //
633 // Continue to receive icmp echo reply packets.
634 //
635 Private->RxToken.Status = EFI_ABORTED;
636
637 Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);
638
639 if (EFI_ERROR (Status)) {
640 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);
641 Private->Status = EFI_ABORTED;
642 }
643 } else {
644 //
645 // All reply have already been received from the dest host.
646 //
647 Private->Status = EFI_SUCCESS;
648 }
649}
650
663 IN PING_PRIVATE_DATA *Private,
664 IN UINT32 TimeStamp,
665 IN UINT16 SequenceNum
666 )
667{
668 EFI_STATUS Status;
670 VOID *TxData;
672 UINT16 HeadSum;
673 UINT16 TempChecksum;
674
675 Request = AllocateZeroPool (Private->BufferSize);
676 if (Request == NULL) {
677 return NULL;
678 }
679
680 TxData = AllocateZeroPool (Private->IpChoice == PING_IP_CHOICE_IP6 ? sizeof (EFI_IP6_TRANSMIT_DATA) : sizeof (EFI_IP4_TRANSMIT_DATA));
681 if (TxData == NULL) {
682 FreePool (Request);
683 return NULL;
684 }
685
687 if (Token == NULL) {
688 FreePool (Request);
689 FreePool (TxData);
690 return NULL;
691 }
692
693 //
694 // Assembly echo request packet.
695 //
696 Request->Type = (UINT8)(Private->IpChoice == PING_IP_CHOICE_IP6 ? ICMP_V6_ECHO_REQUEST : ICMP_V4_ECHO_REQUEST);
697 Request->Code = 0;
698 Request->SequenceNum = SequenceNum;
699 Request->Identifier = 0;
700 Request->Checksum = 0;
701
702 //
703 // Assembly token for transmit.
704 //
705 if (Private->IpChoice == PING_IP_CHOICE_IP6) {
706 Request->TimeStamp = TimeStamp;
707 ((EFI_IP6_TRANSMIT_DATA *)TxData)->ExtHdrsLength = 0;
708 ((EFI_IP6_TRANSMIT_DATA *)TxData)->ExtHdrs = NULL;
709 ((EFI_IP6_TRANSMIT_DATA *)TxData)->OverrideData = 0;
710 ((EFI_IP6_TRANSMIT_DATA *)TxData)->DataLength = Private->BufferSize;
711 ((EFI_IP6_TRANSMIT_DATA *)TxData)->FragmentCount = 1;
712 ((EFI_IP6_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentBuffer = (VOID *)Request;
713 ((EFI_IP6_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;
714 } else {
715 ((EFI_IP4_TRANSMIT_DATA *)TxData)->OptionsLength = 0;
716 ((EFI_IP4_TRANSMIT_DATA *)TxData)->OptionsBuffer = NULL;
717 ((EFI_IP4_TRANSMIT_DATA *)TxData)->OverrideData = 0;
718 ((EFI_IP4_TRANSMIT_DATA *)TxData)->TotalDataLength = Private->BufferSize;
719 ((EFI_IP4_TRANSMIT_DATA *)TxData)->FragmentCount = 1;
720 ((EFI_IP4_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentBuffer = (VOID *)Request;
721 ((EFI_IP4_TRANSMIT_DATA *)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;
722 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[0] = Private->DstAddress[0];
723 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[1] = Private->DstAddress[1];
724 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[2] = Private->DstAddress[2];
725 ((EFI_IP4_TRANSMIT_DATA *)TxData)->DestinationAddress.Addr[3] = Private->DstAddress[3];
726
727 HeadSum = NetChecksum ((UINT8 *)Request, Private->BufferSize);
728 Request->TimeStamp = TimeStamp;
729 TempChecksum = NetChecksum ((UINT8 *)&Request->TimeStamp, sizeof (UINT64));
730 Request->Checksum = (UINT16)(~NetAddChecksum (HeadSum, TempChecksum));
731 }
732
733 Token->Status = EFI_ABORTED;
734 Token->Packet.TxData = TxData;
735
736 Status = gBS->CreateEvent (
737 EVT_NOTIFY_SIGNAL,
738 TPL_CALLBACK,
740 Private,
741 &Token->Event
742 );
743
744 if (EFI_ERROR (Status)) {
745 FreePool (Request);
746 FreePool (TxData);
747 FreePool (Token);
748 return NULL;
749 }
750
751 return Token;
752}
753
766 IN PING_PRIVATE_DATA *Private
767 )
768{
769 EFI_STATUS Status;
770 PING_ICMPX_TX_INFO *TxInfo;
771
772 TxInfo = AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO));
773
774 if (TxInfo == NULL) {
775 return EFI_OUT_OF_RESOURCES;
776 }
777
778 TxInfo->TimeStamp = ReadTime (Private);
779 TxInfo->SequenceNum = (UINT16)(Private->TxCount + 1);
780 TxInfo->Token = PingGenerateToken (
781 Private,
782 TxInfo->TimeStamp,
783 TxInfo->SequenceNum
784 );
785
786 if (TxInfo->Token == NULL) {
787 PingDestroyTxInfo (TxInfo, Private->IpChoice);
788 return EFI_OUT_OF_RESOURCES;
789 }
790
791 ASSERT (Private->ProtocolPointers.Transmit != NULL);
792
793 InsertTailList (&Private->TxList, &TxInfo->Link);
794
795 Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);
796
797 if (EFI_ERROR (Status)) {
798 RemoveEntryList (&TxInfo->Link);
799 PingDestroyTxInfo (TxInfo, Private->IpChoice);
800 return Status;
801 }
802
803 Private->TxCount++;
804
805 return EFI_SUCCESS;
806}
807
819 IN PING_PRIVATE_DATA *Private
820 )
821{
822 EFI_STATUS Status;
823
824 ZeroMem (&Private->RxToken, sizeof (PING_IPX_COMPLETION_TOKEN));
825
826 Status = gBS->CreateEvent (
827 EVT_NOTIFY_SIGNAL,
828 TPL_CALLBACK,
830 Private,
831 &Private->RxToken.Event
832 );
833
834 if (EFI_ERROR (Status)) {
835 return Status;
836 }
837
838 Private->RxToken.Status = EFI_NOT_READY;
839
840 Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);
841 if (EFI_ERROR (Status)) {
842 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);
843 }
844
845 return Status;
846}
847
855VOID
856EFIAPI
858 IN EFI_EVENT Event,
859 IN VOID *Context
860 )
861{
862 EFI_STATUS Status;
863 PING_PRIVATE_DATA *Private;
864 PING_ICMPX_TX_INFO *TxInfo;
865 LIST_ENTRY *Entry;
866 LIST_ENTRY *NextEntry;
867 UINT64 Time;
868
869 Private = (PING_PRIVATE_DATA *)Context;
870 if (Private->Signature != PING_PRIVATE_DATA_SIGNATURE) {
871 Private->Status = EFI_NOT_FOUND;
872 return;
873 }
874
875 //
876 // Retransmit icmp6 echo request packets per second in sendnumber times.
877 //
878 if (Private->TxCount < Private->SendNum) {
879 Status = PingSendEchoRequest (Private);
880 if (Private->TxCount != 0) {
881 if (EFI_ERROR (Status)) {
882 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_SEND_REQUEST), gShellNetwork1HiiHandle, Private->TxCount + 1);
883 }
884 }
885 }
886
887 //
888 // Check whether any icmp6 echo request in the list timeout.
889 //
890 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
891 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);
892 Time = CalculateTick (Private, TxInfo->TimeStamp, ReadTime (Private));
893
894 //
895 // Remove the timeout echo request from txlist.
896 //
897 if (Time > DEFAULT_TIMEOUT) {
898 if (EFI_ERROR (TxInfo->Token->Status)) {
899 Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);
900 }
901
902 //
903 // Remove the timeout icmp6 echo request from list.
904 //
905 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_TIMEOUT), gShellNetwork1HiiHandle, TxInfo->SequenceNum);
906
907 RemoveEntryList (&TxInfo->Link);
908 PingDestroyTxInfo (TxInfo, Private->IpChoice);
909
910 Private->RxCount++;
911 Private->FailedCount++;
912
913 if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {
914 //
915 // All the left icmp6 echo request in the list timeout.
916 //
917 Private->Status = EFI_TIMEOUT;
918 }
919 }
920 }
921}
922
933BOOLEAN
935 IN CONST EFI_IPv4_ADDRESS *Address
936 )
937{
938 return ((BOOLEAN)(Address->Addr[0] == 169 && Address->Addr[1] == 254 && Address->Addr[2] >= 1 && Address->Addr[2] <= 254));
939}
940
949BOOLEAN
951 IN CONST EFI_IPv4_ADDRESS *Address
952 )
953{
954 return ((BOOLEAN)((ReadUnaligned32 ((UINT32 *)&Address->Addr[0])) == 0x00000000));
955}
956
970 IN PING_PRIVATE_DATA *Private
971 )
972{
973 EFI_STATUS Status;
974 UINTN HandleIndex;
975 UINTN HandleNum;
976 EFI_HANDLE *HandleBuffer;
977 BOOLEAN UnspecifiedSrc;
978 EFI_STATUS MediaStatus;
980 VOID *IpXCfg;
981 EFI_IP6_CONFIG_DATA Ip6Config;
982 EFI_IP4_CONFIG_DATA Ip4Config;
983 VOID *IpXInterfaceInfo;
984 UINTN IfInfoSize;
985 EFI_IPv6_ADDRESS *Addr;
986 UINTN AddrIndex;
987
988 HandleBuffer = NULL;
989 UnspecifiedSrc = FALSE;
990 MediaStatus = EFI_SUCCESS;
991 EfiSb = NULL;
992 IpXInterfaceInfo = NULL;
993 IfInfoSize = 0;
994
995 //
996 // Locate all the handles with ip6 service binding protocol.
997 //
998 Status = gBS->LocateHandleBuffer (
1000 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,
1001 NULL,
1002 &HandleNum,
1003 &HandleBuffer
1004 );
1005 if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) {
1006 return EFI_ABORTED;
1007 }
1008
1009 if ((Private->IpChoice == PING_IP_CHOICE_IP6) ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS *)&Private->SrcAddress) : \
1010 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS *)&Private->SrcAddress))
1011 {
1012 //
1013 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1014 //
1015 UnspecifiedSrc = TRUE;
1016 }
1017
1018 //
1019 // Source address is required when pinging a link-local address.
1020 //
1021 if (Private->IpChoice == PING_IP_CHOICE_IP6) {
1022 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {
1023 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);
1024 Status = EFI_INVALID_PARAMETER;
1025 goto ON_ERROR;
1026 }
1027 } else {
1028 ASSERT (Private->IpChoice == PING_IP_CHOICE_IP4);
1029 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {
1030 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);
1031 Status = EFI_INVALID_PARAMETER;
1032 goto ON_ERROR;
1033 }
1034 }
1035
1036 //
1037 // For each ip6 protocol, check interface addresses list.
1038 //
1039 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {
1040 EfiSb = NULL;
1041 IpXInterfaceInfo = NULL;
1042 IfInfoSize = 0;
1043
1044 if (UnspecifiedSrc) {
1045 //
1046 // Check media.
1047 //
1048 NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);
1049 if (MediaStatus != EFI_SUCCESS) {
1050 //
1051 // Skip this one.
1052 //
1053 continue;
1054 }
1055 }
1056
1057 Status = gBS->HandleProtocol (
1058 HandleBuffer[HandleIndex],
1059 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,
1060 (VOID **)&EfiSb
1061 );
1062 if (EFI_ERROR (Status)) {
1063 goto ON_ERROR;
1064 }
1065
1066 //
1067 // Ip6config protocol and ip6 service binding protocol are installed
1068 // on the same handle.
1069 //
1070 Status = gBS->HandleProtocol (
1071 HandleBuffer[HandleIndex],
1072 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ConfigProtocolGuid : &gEfiIp4Config2ProtocolGuid,
1073 (VOID **)&IpXCfg
1074 );
1075
1076 if (EFI_ERROR (Status)) {
1077 goto ON_ERROR;
1078 }
1079
1080 //
1081 // Get the interface information size.
1082 //
1083 if (Private->IpChoice == PING_IP_CHOICE_IP6) {
1084 Status = ((EFI_IP6_CONFIG_PROTOCOL *)IpXCfg)->GetData (
1085 IpXCfg,
1087 &IfInfoSize,
1088 NULL
1089 );
1090 } else {
1091 Status = ((EFI_IP4_CONFIG2_PROTOCOL *)IpXCfg)->GetData (
1092 IpXCfg,
1094 &IfInfoSize,
1095 NULL
1096 );
1097 }
1098
1099 //
1100 // Skip the ones not in current use.
1101 //
1102 if (Status == EFI_NOT_STARTED) {
1103 continue;
1104 }
1105
1106 if (Status != EFI_BUFFER_TOO_SMALL) {
1107 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);
1108 goto ON_ERROR;
1109 }
1110
1111 IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);
1112
1113 if (IpXInterfaceInfo == NULL) {
1114 Status = EFI_OUT_OF_RESOURCES;
1115 goto ON_ERROR;
1116 }
1117
1118 //
1119 // Get the interface info.
1120 //
1121 if (Private->IpChoice == PING_IP_CHOICE_IP6) {
1122 Status = ((EFI_IP6_CONFIG_PROTOCOL *)IpXCfg)->GetData (
1123 IpXCfg,
1125 &IfInfoSize,
1126 IpXInterfaceInfo
1127 );
1128 } else {
1129 Status = ((EFI_IP4_CONFIG2_PROTOCOL *)IpXCfg)->GetData (
1130 IpXCfg,
1132 &IfInfoSize,
1133 IpXInterfaceInfo
1134 );
1135 }
1136
1137 if (EFI_ERROR (Status)) {
1138 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);
1139 goto ON_ERROR;
1140 }
1141
1142 //
1143 // Check whether the source address is one of the interface addresses.
1144 //
1145 if (Private->IpChoice == PING_IP_CHOICE_IP6) {
1146 for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO *)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) {
1147 Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO *)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address);
1148
1149 if (UnspecifiedSrc) {
1150 if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {
1151 //
1152 // Select the interface automatically.
1153 //
1154 CopyMem (&Private->SrcAddress, Addr, sizeof (Private->SrcAddress));
1155 break;
1156 }
1157 } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {
1158 //
1159 // Match a certain interface address.
1160 //
1161 break;
1162 }
1163 }
1164
1165 if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO *)IpXInterfaceInfo)->AddressInfoCount) {
1166 //
1167 // Found a nic handle with right interface address.
1168 //
1169 break;
1170 }
1171 } else {
1172 if (UnspecifiedSrc) {
1173 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress) &&
1174 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress))
1175 {
1176 //
1177 // Select the interface automatically.
1178 //
1179 break;
1180 }
1181 } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress)) {
1182 //
1183 // Match a certain interface address.
1184 //
1185 break;
1186 }
1187 }
1188
1189 FreePool (IpXInterfaceInfo);
1190 IpXInterfaceInfo = NULL;
1191 }
1192
1193 //
1194 // No exact interface address matched.
1195 //
1196
1197 if (HandleIndex == HandleNum) {
1198 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping");
1199 Status = EFI_NOT_FOUND;
1200 goto ON_ERROR;
1201 }
1202
1203 Private->NicHandle = HandleBuffer[HandleIndex];
1204
1205 ASSERT (EfiSb != NULL);
1206 Status = EfiSb->CreateChild (EfiSb, &Private->IpChildHandle);
1207
1208 if (EFI_ERROR (Status)) {
1209 goto ON_ERROR;
1210 }
1211
1212 if (Private->IpChoice == PING_IP_CHOICE_IP6) {
1213 Status = gBS->OpenProtocol (
1214 Private->IpChildHandle,
1215 &gEfiIp6ProtocolGuid,
1216 &Private->IpProtocol,
1218 Private->IpChildHandle,
1219 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1220 );
1221 if (EFI_ERROR (Status)) {
1222 goto ON_ERROR;
1223 }
1224
1225 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));
1226
1227 //
1228 // Configure the ip6 instance for icmp6 packet exchange.
1229 //
1230 Ip6Config.DefaultProtocol = 58;
1231 Ip6Config.AcceptAnyProtocol = FALSE;
1232 Ip6Config.AcceptIcmpErrors = TRUE;
1233 Ip6Config.AcceptPromiscuous = FALSE;
1234 Ip6Config.TrafficClass = 0;
1235 Ip6Config.HopLimit = 128;
1236 Ip6Config.FlowLabel = 0;
1237 Ip6Config.ReceiveTimeout = 0;
1238 Ip6Config.TransmitTimeout = 0;
1239
1240 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);
1241 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);
1242
1243 Status = ((EFI_IP6_PROTOCOL *)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config);
1244
1245 if (EFI_ERROR (Status)) {
1246 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);
1247 goto ON_ERROR;
1248 }
1249
1250 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Transmit;
1251 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Receive;
1252 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Cancel;
1253 Private->ProtocolPointers.Poll = (PING_IPX_POLL)((EFI_IP6_PROTOCOL *)Private->IpProtocol)->Poll;
1254 } else {
1255 Status = gBS->OpenProtocol (
1256 Private->IpChildHandle,
1257 &gEfiIp4ProtocolGuid,
1258 &Private->IpProtocol,
1260 Private->IpChildHandle,
1261 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1262 );
1263 if (EFI_ERROR (Status)) {
1264 goto ON_ERROR;
1265 }
1266
1267 ZeroMem (&Ip4Config, sizeof (EFI_IP4_CONFIG_DATA));
1268
1269 //
1270 // Configure the ip4 instance for icmp4 packet exchange.
1271 //
1272 Ip4Config.DefaultProtocol = 1;
1273 Ip4Config.AcceptAnyProtocol = FALSE;
1274 Ip4Config.AcceptBroadcast = FALSE;
1275 Ip4Config.AcceptIcmpErrors = TRUE;
1276 Ip4Config.AcceptPromiscuous = FALSE;
1277 Ip4Config.DoNotFragment = FALSE;
1278 Ip4Config.RawData = FALSE;
1279 Ip4Config.ReceiveTimeout = 0;
1280 Ip4Config.TransmitTimeout = 0;
1281 Ip4Config.UseDefaultAddress = TRUE;
1282 Ip4Config.TimeToLive = 128;
1283 Ip4Config.TypeOfService = 0;
1284
1285 Status = ((EFI_IP4_PROTOCOL *)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config);
1286
1287 if (EFI_ERROR (Status)) {
1288 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);
1289 goto ON_ERROR;
1290 }
1291
1292 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Transmit;
1293 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Receive;
1294 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Cancel;
1295 Private->ProtocolPointers.Poll = (PING_IPX_POLL)((EFI_IP4_PROTOCOL *)Private->IpProtocol)->Poll;
1296 }
1297
1298 if (HandleBuffer != NULL) {
1299 FreePool (HandleBuffer);
1300 }
1301
1302 return EFI_SUCCESS;
1303
1304ON_ERROR:
1305 if (HandleBuffer != NULL) {
1306 FreePool (HandleBuffer);
1307 }
1308
1309 if (IpXInterfaceInfo != NULL) {
1310 FreePool (IpXInterfaceInfo);
1311 }
1312
1313 if ((EfiSb != NULL) && (Private->IpChildHandle != NULL)) {
1314 EfiSb->DestroyChild (EfiSb, Private->IpChildHandle);
1315 }
1316
1317 return Status;
1318}
1319
1326VOID
1328 IN PING_PRIVATE_DATA *Private
1329 )
1330{
1331 EFI_STATUS Status;
1333
1334 gBS->CloseProtocol (
1335 Private->IpChildHandle,
1336 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ProtocolGuid : &gEfiIp4ProtocolGuid,
1338 Private->IpChildHandle
1339 );
1340
1341 Status = gBS->HandleProtocol (
1342 Private->NicHandle,
1343 Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,
1344 (VOID **)&IpSb
1345 );
1346
1347 if (!EFI_ERROR (Status)) {
1348 IpSb->DestroyChild (IpSb, Private->IpChildHandle);
1349 }
1350}
1351
1366 IN UINT32 SendNumber,
1367 IN UINT32 BufferSize,
1368 IN EFI_IPv6_ADDRESS *SrcAddress,
1369 IN EFI_IPv6_ADDRESS *DstAddress,
1370 IN UINT32 IpChoice
1371 )
1372{
1373 EFI_STATUS Status;
1374 PING_PRIVATE_DATA *Private;
1375 PING_ICMPX_TX_INFO *TxInfo;
1376 LIST_ENTRY *Entry;
1377 LIST_ENTRY *NextEntry;
1378 SHELL_STATUS ShellStatus;
1379
1380 ShellStatus = SHELL_SUCCESS;
1381 Private = AllocateZeroPool (sizeof (PING_PRIVATE_DATA));
1382
1383 if (Private == NULL) {
1384 return (SHELL_OUT_OF_RESOURCES);
1385 }
1386
1387 Private->IpChoice = IpChoice;
1388 Private->Signature = PING_PRIVATE_DATA_SIGNATURE;
1389 Private->SendNum = SendNumber;
1390 Private->BufferSize = BufferSize;
1391 Private->RttMin = ~((UINT64)(0x0));
1392 Private->Status = EFI_NOT_READY;
1393
1394 CopyMem (&Private->SrcAddress, SrcAddress, sizeof (Private->SrcAddress));
1395 CopyMem (&Private->DstAddress, DstAddress, sizeof (Private->DstAddress));
1396
1397 InitializeListHead (&Private->TxList);
1398
1399 //
1400 // Open and configure a ip instance for us.
1401 //
1402 Status = PingCreateIpInstance (Private);
1403
1404 if (EFI_ERROR (Status)) {
1405 ShellStatus = SHELL_ACCESS_DENIED;
1406 goto ON_EXIT;
1407 }
1408
1409 //
1410 // Print the command line itself.
1411 //
1412 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_START), gShellNetwork1HiiHandle, mDstString, Private->BufferSize);
1413 //
1414 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1415 //
1416 Status = Ping6ReceiveEchoReply (Private);
1417
1418 if (EFI_ERROR (Status)) {
1419 ShellStatus = SHELL_ACCESS_DENIED;
1420 goto ON_EXIT;
1421 }
1422
1423 //
1424 // Create and start timer to send icmp6 echo request packet per second.
1425 //
1426 Status = gBS->CreateEvent (
1427 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1428 TPL_CALLBACK,
1430 Private,
1431 &Private->Timer
1432 );
1433
1434 if (EFI_ERROR (Status)) {
1435 ShellStatus = SHELL_ACCESS_DENIED;
1436 goto ON_EXIT;
1437 }
1438
1439 //
1440 // Start a timer to calculate the RTT.
1441 //
1442 Status = PingInitRttTimer (Private);
1443 if (EFI_ERROR (Status)) {
1444 ShellStatus = SHELL_ACCESS_DENIED;
1445 goto ON_EXIT;
1446 }
1447
1448 //
1449 // Create a ipv6 token to send the first icmp6 echo request packet.
1450 //
1451 Status = PingSendEchoRequest (Private);
1452 //
1453 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1454 //
1455 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
1456 ShellStatus = SHELL_ACCESS_DENIED;
1457 if (Status == EFI_NOT_FOUND) {
1458 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOSOURCE_INDO), gShellNetwork1HiiHandle, mDstString);
1459 } else if (Status == RETURN_NO_MAPPING) {
1460 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString);
1461 } else {
1462 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, L"ping", Status);
1463 }
1464
1465 goto ON_EXIT;
1466 }
1467
1468 Status = gBS->SetTimer (
1469 Private->Timer,
1471 ONE_SECOND
1472 );
1473
1474 if (EFI_ERROR (Status)) {
1475 ShellStatus = SHELL_ACCESS_DENIED;
1476 goto ON_EXIT;
1477 }
1478
1479 //
1480 // Control the ping6 process by two factors:
1481 // 1. Hot key
1482 // 2. Private->Status
1483 // 2.1. success means all icmp6 echo request packets get reply packets.
1484 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1485 // 2.3. noready means ping6 process is on-the-go.
1486 //
1487 while (Private->Status == EFI_NOT_READY) {
1488 Status = Private->ProtocolPointers.Poll (Private->IpProtocol);
1490 Private->Status = EFI_ABORTED;
1491 goto ON_STAT;
1492 }
1493 }
1494
1495ON_STAT:
1496 //
1497 // Display the statistics in all.
1498 //
1499 gBS->SetTimer (Private->Timer, TimerCancel, 0);
1500
1501 if (Private->TxCount != 0) {
1503 -1,
1504 -1,
1505 NULL,
1506 STRING_TOKEN (STR_PING_STAT),
1507 gShellNetwork1HiiHandle,
1508 Private->TxCount,
1509 (Private->RxCount - Private->FailedCount),
1510 (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)),
1511 Private->RttSum
1512 );
1513 }
1514
1515 if (Private->RxCount > Private->FailedCount) {
1517 -1,
1518 -1,
1519 NULL,
1520 STRING_TOKEN (STR_PING_RTT),
1521 gShellNetwork1HiiHandle,
1522 Private->RttMin,
1523 Private->RttMin + Private->TimerPeriod,
1524 Private->RttMax,
1525 Private->RttMax + Private->TimerPeriod,
1526 DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL),
1527 DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod
1528 );
1529 }
1530
1531ON_EXIT:
1532
1533 if (Private != NULL) {
1534 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
1535 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);
1536
1537 if ((Private->IpProtocol != NULL) && (Private->ProtocolPointers.Cancel != NULL)) {
1538 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);
1539 }
1540
1541 RemoveEntryList (&TxInfo->Link);
1542 PingDestroyTxInfo (TxInfo, Private->IpChoice);
1543 }
1544
1545 PingFreeRttTimer (Private);
1546
1547 if (Private->Timer != NULL) {
1548 gBS->CloseEvent (Private->Timer);
1549 }
1550
1551 if ((Private->IpProtocol != NULL) && (Private->ProtocolPointers.Cancel != NULL)) {
1552 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, &Private->RxToken);
1553 }
1554
1555 if (Private->RxToken.Event != NULL) {
1556 gBS->CloseEvent (Private->RxToken.Event);
1557 }
1558
1559 if (Private->IpChildHandle != NULL) {
1560 Ping6DestroyIp6Instance (Private);
1561 }
1562
1563 FreePool (Private);
1564 }
1565
1566 return ShellStatus;
1567}
1568
1580EFIAPI
1582 IN EFI_HANDLE ImageHandle,
1583 IN EFI_SYSTEM_TABLE *SystemTable
1584 )
1585{
1586 EFI_STATUS Status;
1587 SHELL_STATUS ShellStatus;
1588 EFI_IPv6_ADDRESS DstAddress;
1589 EFI_IPv6_ADDRESS SrcAddress;
1590 UINT64 BufferSize;
1591 UINTN SendNumber;
1592 LIST_ENTRY *ParamPackage;
1593 CONST CHAR16 *ValueStr;
1594 UINTN NonOptionCount;
1595 UINT32 IpChoice;
1596 CHAR16 *ProblemParam;
1597
1598 //
1599 // we use IPv6 buffers to hold items...
1600 // make sure this is enough space!
1601 //
1602 ASSERT (sizeof (EFI_IPv4_ADDRESS) <= sizeof (EFI_IPv6_ADDRESS));
1603 ASSERT (sizeof (EFI_IP4_COMPLETION_TOKEN) <= sizeof (EFI_IP6_COMPLETION_TOKEN));
1604
1605 IpChoice = PING_IP_CHOICE_IP4;
1606
1607 ShellStatus = SHELL_SUCCESS;
1608 ProblemParam = NULL;
1609
1610 Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);
1611 if (EFI_ERROR (Status)) {
1612 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);
1613 ShellStatus = SHELL_INVALID_PARAMETER;
1614 goto ON_EXIT;
1615 }
1616
1617 if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) {
1618 IpChoice = PING_IP_CHOICE_IP6;
1619 }
1620
1621 //
1622 // Parse the parameter of count number.
1623 //
1624 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");
1625 if (ValueStr != NULL) {
1626 SendNumber = ShellStrToUintn (ValueStr);
1627
1628 //
1629 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1630 //
1631 if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) {
1632 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
1633 ShellStatus = SHELL_INVALID_PARAMETER;
1634 goto ON_EXIT;
1635 }
1636 } else {
1637 SendNumber = DEFAULT_SEND_COUNT;
1638 }
1639
1640 //
1641 // Parse the parameter of buffer size.
1642 //
1643 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");
1644 if (ValueStr != NULL) {
1645 BufferSize = ShellStrToUintn (ValueStr);
1646
1647 //
1648 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1649 //
1650 if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) {
1651 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
1652 ShellStatus = SHELL_INVALID_PARAMETER;
1653 goto ON_EXIT;
1654 }
1655 } else {
1656 BufferSize = DEFAULT_BUFFER_SIZE;
1657 }
1658
1659 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));
1660 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));
1661
1662 //
1663 // Parse the parameter of source ip address.
1664 //
1665 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");
1666 if (ValueStr == NULL) {
1667 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s");
1668 }
1669
1670 if (ValueStr != NULL) {
1671 mSrcString = ValueStr;
1672 if (IpChoice == PING_IP_CHOICE_IP6) {
1673 Status = NetLibStrToIp6 (ValueStr, &SrcAddress);
1674 } else {
1675 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS *)&SrcAddress);
1676 }
1677
1678 if (EFI_ERROR (Status)) {
1679 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
1680 ShellStatus = SHELL_INVALID_PARAMETER;
1681 goto ON_EXIT;
1682 }
1683 }
1684
1685 //
1686 // Parse the parameter of destination ip address.
1687 //
1688 NonOptionCount = ShellCommandLineGetCount (ParamPackage);
1689 if (NonOptionCount < 2) {
1690 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping");
1691 ShellStatus = SHELL_INVALID_PARAMETER;
1692 goto ON_EXIT;
1693 }
1694
1695 if (NonOptionCount > 2) {
1696 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping");
1697 ShellStatus = SHELL_INVALID_PARAMETER;
1698 goto ON_EXIT;
1699 }
1700
1701 ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);
1702 if (ValueStr != NULL) {
1703 mDstString = ValueStr;
1704 if (IpChoice == PING_IP_CHOICE_IP6) {
1705 Status = NetLibStrToIp6 (ValueStr, &DstAddress);
1706 } else {
1707 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS *)&DstAddress);
1708 }
1709
1710 if (EFI_ERROR (Status)) {
1711 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
1712 ShellStatus = SHELL_INVALID_PARAMETER;
1713 goto ON_EXIT;
1714 }
1715 }
1716
1717 //
1718 // Enter into ping process.
1719 //
1720 ShellStatus = ShellPing (
1721 (UINT32)SendNumber,
1722 (UINT32)BufferSize,
1723 &SrcAddress,
1724 &DstAddress,
1725 IpChoice
1726 );
1727
1728ON_EXIT:
1729 ShellCommandLineFreeVarList (ParamPackage);
1730 return ShellStatus;
1731}
UINT64 UINTN
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
UINT64 EFIAPI DivU64x64Remainder(IN UINT64 Dividend, IN UINT64 Divisor, OUT UINT64 *Remainder OPTIONAL)
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
UINT32 EFIAPI ReadUnaligned32(IN CONST UINT32 *Buffer)
Definition: Unaligned.c:145
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
@ Ip4Config2DataTypeInterfaceInfo
Definition: Ip4Config2.h:35
#define ICMP_V6_ECHO_REQUEST
Definition: Ip6.h:90
@ Ip6ConfigDataTypeInterfaceInfo
Definition: Ip6Config.h:32
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define RETURN_NO_MAPPING
Definition: Base.h:1157
#define OPTIONAL
Definition: Base.h:290
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define BASE_CR(Record, TYPE, Field)
Definition: Base.h:891
#define MAX(a, b)
Definition: Base.h:992
SHELL_STATUS
Definition: Shell.h:21
@ SHELL_OUT_OF_RESOURCES
Definition: Shell.h:73
@ SHELL_ACCESS_DENIED
Definition: Shell.h:106
@ SHELL_SUCCESS
Definition: Shell.h:25
@ SHELL_INVALID_PARAMETER
Definition: Shell.h:35
BOOLEAN EFIAPI NetIp6IsLinkLocalAddr(IN EFI_IPv6_ADDRESS *Ip6)
Definition: DxeNetLib.c:796
UINT16 EFIAPI NetAddChecksum(IN UINT16 Checksum1, IN UINT16 Checksum2)
Definition: NetBuffer.c:1658
BOOLEAN EFIAPI NetIp6IsUnspecifiedAddr(IN EFI_IPv6_ADDRESS *Ip6)
Definition: DxeNetLib.c:766
EFI_STATUS EFIAPI NetLibDetectMediaWaitTimeout(IN EFI_HANDLE ServiceHandle, IN UINT64 Timeout, OUT EFI_STATUS *MediaState)
Definition: DxeNetLib.c:2683
EFI_STATUS EFIAPI NetLibStrToIp4(IN CONST CHAR16 *String, OUT EFI_IPv4_ADDRESS *Ip4Address)
Definition: DxeNetLib.c:3125
EFI_STATUS EFIAPI NetLibStrToIp6(IN CONST CHAR16 *String, OUT EFI_IPv6_ADDRESS *Ip6Address)
Definition: DxeNetLib.c:3154
VOID EFIAPI Ping6OnEchoRequestSent(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping.c:522
SHELL_STATUS EFIAPI ShellCommandRunPing(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: Ping.c:1581
PING_IPX_COMPLETION_TOKEN * PingGenerateToken(IN PING_PRIVATE_DATA *Private, IN UINT32 TimeStamp, IN UINT16 SequenceNum)
Definition: Ping.c:662
VOID Ping6DestroyIp6Instance(IN PING_PRIVATE_DATA *Private)
Definition: Ping.c:1327
VOID EFIAPI Ping6OnEchoReplyReceived(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping.c:538
UINT32 GetTimerPeriod(VOID)
Definition: Ping.c:253
VOID PingDestroyTxInfo(IN PING_ICMPX_TX_INFO *TxInfo, IN UINT32 IpChoice)
Definition: Ping.c:417
UINT32 CalculateTick(PING_PRIVATE_DATA *Private, IN UINT32 Begin, IN UINT32 End)
Definition: Ping.c:397
STATIC CONST SHELL_PARAM_ITEM PingParamList[]
Definition: Ping.c:190
EFI_STATUS Ping6ReceiveEchoReply(IN PING_PRIVATE_DATA *Private)
Definition: Ping.c:818
EFI_STATUS Ping6MatchEchoReply(IN PING_PRIVATE_DATA *Private, IN ICMPX_ECHO_REQUEST_REPLY *Packet)
Definition: Ping.c:487
VOID PingFreeRttTimer(PING_PRIVATE_DATA *Private)
Definition: Ping.c:361
UINT16 NetChecksum(IN UINT8 *Buffer, IN UINT32 Length)
Definition: Ping.c:149
BOOLEAN PingNetIp4IsUnspecifiedAddr(IN CONST EFI_IPv4_ADDRESS *Address)
Definition: Ping.c:950
BOOLEAN PingNetIp4IsLinkLocalAddr(IN CONST EFI_IPv4_ADDRESS *Address)
Definition: Ping.c:934
VOID EFIAPI Ping6OnTimerRoutine(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping.c:857
SHELL_STATUS ShellPing(IN UINT32 SendNumber, IN UINT32 BufferSize, IN EFI_IPv6_ADDRESS *SrcAddress, IN EFI_IPv6_ADDRESS *DstAddress, IN UINT32 IpChoice)
Definition: Ping.c:1365
EFI_STATUS PingCreateIpInstance(IN PING_PRIVATE_DATA *Private)
Definition: Ping.c:969
VOID EFIAPI RttTimerTickRoutine(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping.c:232
UINT32 ReadTime(PING_PRIVATE_DATA *Private)
Definition: Ping.c:379
EFI_STATUS PingInitRttTimer(PING_PRIVATE_DATA *Private)
Definition: Ping.c:318
EFI_STATUS PingSendEchoRequest(IN PING_PRIVATE_DATA *Private)
Definition: Ping.c:765
CONST CHAR16 *EFIAPI ShellCommandLineGetValue(IN CONST LIST_ENTRY *CheckPackage, IN CHAR16 *KeyString)
UINTN EFIAPI ShellStrToUintn(IN CONST CHAR16 *String)
BOOLEAN EFIAPI ShellGetExecutionBreakFlag(VOID)
EFI_STATUS EFIAPI ShellPrintHiiEx(IN INT32 Col OPTIONAL, IN INT32 Row OPTIONAL, IN CONST CHAR8 *Language OPTIONAL, IN CONST EFI_STRING_ID HiiFormatStringId, IN CONST EFI_HII_HANDLE HiiFormatHandle,...)
BOOLEAN EFIAPI ShellCommandLineGetFlag(IN CONST LIST_ENTRY *CONST CheckPackage, IN CONST CHAR16 *CONST KeyString)
@ TypeValue
A flag that has some data following it with a space (IE "-a 1").
Definition: ShellLib.h:700
@ TypeFlag
A flag that is present or not present only (IE "-a").
Definition: ShellLib.h:699
EFI_STATUS EFIAPI ShellCommandLineParseEx(IN CONST SHELL_PARAM_ITEM *CheckList, OUT LIST_ENTRY **CheckPackage, OUT CHAR16 **ProblemParam OPTIONAL, IN BOOLEAN AutoPageBreak, IN BOOLEAN AlwaysAllowNumbers)
VOID EFIAPI ShellCommandLineFreeVarList(IN LIST_ENTRY *CheckPackage)
CONST CHAR16 *EFIAPI ShellCommandLineGetRawValue(IN CONST LIST_ENTRY *CONST CheckPackage, IN UINTN Position)
UINTN EFIAPI ShellCommandLineGetCount(IN CONST LIST_ENTRY *CheckPackage)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_HANDLE gImageHandle
EFI_BOOT_SERVICES * gBS
#define STRING_TOKEN(t)
@ TimerCancel
Definition: UefiSpec.h:531
@ TimerPeriodic
Definition: UefiSpec.h:535
@ ByProtocol
Definition: UefiSpec.h:1518
VOID * FragmentBuffer
Pointer to fragment data. This field may not be set to NULL.
Definition: Ip6.h:416
EFI_IP6_FRAGMENT_DATA FragmentTable[1]
Definition: Ip6.h:510
EFI_IP6_OVERRIDE_DATA * OverrideData
Definition: Ip6.h:482
UINT32 FragmentCount
Definition: Ip6.h:506
BOOLEAN AcceptBroadcast
Definition: Ip4.h:80
UINT8 TypeOfService
Definition: Ip4.h:102
UINT32 ReceiveTimeout
Definition: Ip4.h:121
UINT8 TimeToLive
Definition: Ip4.h:106
BOOLEAN AcceptPromiscuous
Definition: Ip4.h:86
BOOLEAN DoNotFragment
Definition: Ip4.h:110
BOOLEAN AcceptAnyProtocol
Definition: Ip4.h:69
UINT8 DefaultProtocol
Definition: Ip4.h:63
BOOLEAN AcceptIcmpErrors
Definition: Ip4.h:74
BOOLEAN RawData
Definition: Ip4.h:115
UINT32 TransmitTimeout
Definition: Ip4.h:127
BOOLEAN UseDefaultAddress
Definition: Ip4.h:90
BOOLEAN AcceptIcmpErrors
Definition: Ip6.h:157
UINT8 TrafficClass
Definition: Ip6.h:193
UINT32 FlowLabel
Definition: Ip6.h:202
UINT32 ReceiveTimeout
Definition: Ip6.h:208
UINT8 DefaultProtocol
Definition: Ip6.h:144
UINT8 HopLimit
Definition: Ip6.h:197
BOOLEAN AcceptAnyProtocol
Definition: Ip6.h:152
EFI_IPv6_ADDRESS DestinationAddress
Definition: Ip6.h:168
EFI_IPv6_ADDRESS StationAddress
Definition: Ip6.h:188
UINT32 TransmitTimeout
Definition: Ip6.h:214
BOOLEAN AcceptPromiscuous
Definition: Ip6.h:163