TianoCore EDK2 master
Loading...
Searching...
No Matches
Ping6.c
Go to the documentation of this file.
1
11
12#define PING6_DEFAULT_TIMEOUT 5000
13#define PING6_MAX_SEND_NUMBER 10000
14#define PING6_MAX_BUFFER_SIZE 32768
15#define PING6_ONE_SECOND 10000000
16#define STALL_1_MILLI_SECOND 1000
17
18#pragma pack(1)
19
21 UINT8 Type;
22 UINT8 Code;
23 UINT16 Checksum;
24 UINT16 Identifier;
25 UINT16 SequenceNum;
26 UINT32 TimeStamp;
27 UINT8 Data[1];
29
30#pragma pack()
31
32typedef struct _PING6_ICMP6_TX_INFO {
33 LIST_ENTRY Link;
34 UINT16 SequenceNum;
35 UINT32 TimeStamp;
38
39typedef struct _PING6_PRIVATE_DATA {
40 EFI_HANDLE ImageHandle;
41 EFI_HANDLE NicHandle;
42 EFI_HANDLE Ip6ChildHandle;
44 EFI_EVENT Timer;
45
46 UINT32 TimerPeriod;
47 UINT32 RttTimerTick;
48 EFI_EVENT RttTimer;
49
50 EFI_STATUS Status;
51 LIST_ENTRY TxList;
53 UINT16 RxCount;
54 UINT16 TxCount;
55 UINT64 RttSum;
56 UINT64 RttMin;
57 UINT64 RttMax;
58 UINT32 SequenceNum;
59
60 EFI_IPv6_ADDRESS SrcAddress;
61 EFI_IPv6_ADDRESS DstAddress;
62 UINT32 SendNum;
63 UINT32 BufferSize;
65
66SHELL_PARAM_ITEM Ping6ParamList[] = {
67 {
68 L"-l",
70 },
71 {
72 L"-n",
74 },
75 {
76 L"-s",
78 },
79 {
80 L"-?",
82 },
83 {
84 NULL,
85 TypeMax
86 },
87};
88
89//
90// Global Variables in Ping6 application.
91//
92CONST CHAR16 *mIp6DstString;
93CONST CHAR16 *mIp6SrcString;
95
103VOID
104EFIAPI
106 IN EFI_EVENT Event,
107 IN VOID *Context
108 )
109{
110 UINT32 *RttTimerTick;
111
112 RttTimerTick = (UINT32 *)Context;
113 (*RttTimerTick)++;
114}
115
125UINT32
127 VOID
128 )
129{
130 EFI_STATUS Status;
131 UINT32 RttTimerTick;
132 EFI_EVENT TimerEvent;
133 UINT32 StallCounter;
134 EFI_TPL OldTpl;
135
136 RttTimerTick = 0;
137 StallCounter = 0;
138
139 Status = gBS->CreateEvent (
140 EVT_TIMER | EVT_NOTIFY_SIGNAL,
141 TPL_NOTIFY,
143 &RttTimerTick,
144 &TimerEvent
145 );
146 if (EFI_ERROR (Status)) {
147 return 0;
148 }
149
150 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
151 Status = gBS->SetTimer (
152 TimerEvent,
154 TICKS_PER_MS
155 );
156 if (EFI_ERROR (Status)) {
157 gBS->CloseEvent (TimerEvent);
158 return 0;
159 }
160
161 while (RttTimerTick < 10) {
162 gBS->Stall (STALL_1_MILLI_SECOND);
163 ++StallCounter;
164 }
165
166 gBS->RestoreTPL (OldTpl);
167
168 gBS->SetTimer (TimerEvent, TimerCancel, 0);
169 gBS->CloseEvent (TimerEvent);
170
171 return StallCounter / RttTimerTick;
172}
173
185 IN PING6_PRIVATE_DATA *Private
186 )
187{
188 EFI_STATUS Status;
189
190 Private->TimerPeriod = Ping6GetTimerPeriod ();
191 if (Private->TimerPeriod == 0) {
192 return EFI_ABORTED;
193 }
194
195 Private->RttTimerTick = 0;
196 Status = gBS->CreateEvent (
197 EVT_TIMER | EVT_NOTIFY_SIGNAL,
198 TPL_NOTIFY,
200 &Private->RttTimerTick,
201 &Private->RttTimer
202 );
203 if (EFI_ERROR (Status)) {
204 return Status;
205 }
206
207 Status = gBS->SetTimer (
208 Private->RttTimer,
210 TICKS_PER_MS
211 );
212 if (EFI_ERROR (Status)) {
213 gBS->CloseEvent (Private->RttTimer);
214 return Status;
215 }
216
217 return EFI_SUCCESS;
218}
219
226VOID
228 IN PING6_PRIVATE_DATA *Private
229 )
230{
231 if (Private->RttTimer != NULL) {
232 gBS->SetTimer (Private->RttTimer, TimerCancel, 0);
233 gBS->CloseEvent (Private->RttTimer);
234 }
235}
236
244UINT32
246 IN PING6_PRIVATE_DATA *Private
247 )
248{
249 return Private->RttTimerTick;
250}
251
262UINT32
264 IN PING6_PRIVATE_DATA *Private,
265 IN UINT32 Begin,
266 IN UINT32 End
267 )
268{
269 if (End < Begin) {
270 return (0);
271 }
272
273 return (End - Begin) * Private->TimerPeriod;
274}
275
282VOID
284 IN PING6_ICMP6_TX_INFO *TxInfo
285 )
286{
287 EFI_IP6_TRANSMIT_DATA *TxData;
288 EFI_IP6_FRAGMENT_DATA *FragData;
289 UINTN Index;
290
291 ASSERT (TxInfo != NULL);
292
293 if (TxInfo->Token != NULL) {
294 if (TxInfo->Token->Event != NULL) {
295 gBS->CloseEvent (TxInfo->Token->Event);
296 }
297
298 TxData = TxInfo->Token->Packet.TxData;
299 if (TxData != NULL) {
300 if (TxData->OverrideData != NULL) {
301 FreePool (TxData->OverrideData);
302 }
303
304 if (TxData->ExtHdrs != NULL) {
305 FreePool (TxData->ExtHdrs);
306 }
307
308 for (Index = 0; Index < TxData->FragmentCount; Index++) {
309 FragData = TxData->FragmentTable[Index].FragmentBuffer;
310 if (FragData != NULL) {
311 FreePool (FragData);
312 }
313 }
314 }
315
316 FreePool (TxInfo->Token);
317 }
318
319 FreePool (TxInfo);
320}
321
334 IN PING6_PRIVATE_DATA *Private,
336 )
337{
338 PING6_ICMP6_TX_INFO *TxInfo;
339 LIST_ENTRY *Entry;
340 LIST_ENTRY *NextEntry;
341
342 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
343 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);
344
345 if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) {
346 Private->RxCount++;
347 RemoveEntryList (&TxInfo->Link);
348 Ping6DestroyTxInfo (TxInfo);
349 return EFI_SUCCESS;
350 }
351 }
352
353 return EFI_NOT_FOUND;
354}
355
366VOID
367EFIAPI
369 IN EFI_EVENT Event,
370 IN VOID *Context
371 )
372{
373}
374
382VOID
383EFIAPI
385 IN EFI_EVENT Event,
386 IN VOID *Context
387 )
388{
389 EFI_STATUS Status;
390 PING6_PRIVATE_DATA *Private;
392 EFI_IP6_RECEIVE_DATA *RxData;
394 UINT32 PayLoad;
395 UINT32 Rtt;
396
397 Private = (PING6_PRIVATE_DATA *)Context;
398
399 if (Private->Status == EFI_ABORTED) {
400 return;
401 }
402
403 RxToken = &Private->RxToken;
404 RxData = RxToken->Packet.RxData;
405 Reply = RxData->FragmentTable[0].FragmentBuffer;
406 PayLoad = RxData->DataLength;
407
408 if (RxData->Header->NextHeader != IP6_ICMP) {
409 goto ON_EXIT;
410 }
411
412 if (!IP6_IS_MULTICAST (&Private->DstAddress) &&
413 !EFI_IP6_EQUAL (&RxData->Header->SourceAddress, &Private->DstAddress))
414 {
415 goto ON_EXIT;
416 }
417
418 if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) {
419 goto ON_EXIT;
420 }
421
422 if (PayLoad != Private->BufferSize) {
423 goto ON_EXIT;
424 }
425
426 //
427 // Check whether the reply matches the sent request before.
428 //
429 Status = Ping6OnMatchEchoReply (Private, Reply);
430 if (EFI_ERROR (Status)) {
431 goto ON_EXIT;
432 }
433
434 //
435 // Display statistics on this icmp6 echo reply packet.
436 //
437 Rtt = Ping6CalculateTick (Private, Reply->TimeStamp, Ping6ReadTime (Private));
438
439 Private->RttSum += Rtt;
440 Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;
441 Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax;
442
444 -1,
445 -1,
446 NULL,
447 STRING_TOKEN (STR_PING6_REPLY_INFO),
448 gShellNetwork2HiiHandle,
449 PayLoad,
450 mIp6DstString,
451 Reply->SequenceNum,
452 RxData->Header->HopLimit,
453 Rtt,
454 Rtt + Private->TimerPeriod
455 );
456
457ON_EXIT:
458
459 if (Private->RxCount < Private->SendNum) {
460 //
461 // Continue to receive icmp6 echo reply packets.
462 //
463 RxToken->Status = EFI_ABORTED;
464
465 Status = Private->Ip6->Receive (Private->Ip6, RxToken);
466
467 if (EFI_ERROR (Status)) {
468 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status);
469 Private->Status = EFI_ABORTED;
470 }
471 } else {
472 //
473 // All reply have already been received from the dest host.
474 //
475 Private->Status = EFI_SUCCESS;
476 }
477
478 //
479 // Singal to recycle the each rxdata here, not at the end of process.
480 //
481 gBS->SignalEvent (RxData->RecycleSignal);
482}
483
496 IN PING6_PRIVATE_DATA *Private,
497 IN UINT32 TimeStamp,
498 IN UINT16 SequenceNum
499 )
500{
501 EFI_STATUS Status;
503 EFI_IP6_TRANSMIT_DATA *TxData;
505
506 Request = AllocateZeroPool (Private->BufferSize);
507
508 if (Request == NULL) {
509 return NULL;
510 }
511
512 //
513 // Assembly icmp6 echo request packet.
514 //
515 Request->Type = ICMP_V6_ECHO_REQUEST;
516 Request->Code = 0;
517 Request->SequenceNum = SequenceNum;
518 Request->TimeStamp = TimeStamp;
519 Request->Identifier = 0;
520 //
521 // Leave check sum to ip6 layer, since it has no idea of source address
522 // selection.
523 //
524 Request->Checksum = 0;
525
526 TxData = AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA));
527
528 if (TxData == NULL) {
529 FreePool (Request);
530 return NULL;
531 }
532
533 //
534 // Assembly ipv6 token for transmit.
535 //
536 TxData->OverrideData = 0;
537 TxData->ExtHdrsLength = 0;
538 TxData->ExtHdrs = NULL;
539 TxData->DataLength = Private->BufferSize;
540 TxData->FragmentCount = 1;
541 TxData->FragmentTable[0].FragmentBuffer = (VOID *)Request;
542 TxData->FragmentTable[0].FragmentLength = Private->BufferSize;
543
545
546 if (Token == NULL) {
547 FreePool (Request);
548 FreePool (TxData);
549 return NULL;
550 }
551
552 Token->Status = EFI_ABORTED;
553 Token->Packet.TxData = TxData;
554
555 Status = gBS->CreateEvent (
556 EVT_NOTIFY_SIGNAL,
557 TPL_CALLBACK,
559 Private,
560 &Token->Event
561 );
562
563 if (EFI_ERROR (Status)) {
564 FreePool (Request);
565 FreePool (TxData);
566 FreePool (Token);
567 return NULL;
568 }
569
570 return Token;
571}
572
585 IN PING6_PRIVATE_DATA *Private
586 )
587{
588 EFI_STATUS Status;
589 PING6_ICMP6_TX_INFO *TxInfo;
590
591 TxInfo = AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO));
592
593 if (TxInfo == NULL) {
594 return EFI_OUT_OF_RESOURCES;
595 }
596
597 TxInfo->TimeStamp = Ping6ReadTime (Private);
598 TxInfo->SequenceNum = (UINT16)(Private->TxCount + 1);
599
600 TxInfo->Token = Ping6GenerateToken (
601 Private,
602 TxInfo->TimeStamp,
603 TxInfo->SequenceNum
604 );
605
606 if (TxInfo->Token == NULL) {
607 Ping6DestroyTxInfo (TxInfo);
608 return EFI_OUT_OF_RESOURCES;
609 }
610
611 Status = Private->Ip6->Transmit (Private->Ip6, TxInfo->Token);
612
613 if (EFI_ERROR (Status)) {
614 Ping6DestroyTxInfo (TxInfo);
615 return Status;
616 }
617
618 InsertTailList (&Private->TxList, &TxInfo->Link);
619 Private->TxCount++;
620
621 return EFI_SUCCESS;
622}
623
635 IN PING6_PRIVATE_DATA *Private
636 )
637{
638 EFI_STATUS Status;
639
640 ZeroMem (&Private->RxToken, sizeof (EFI_IP6_COMPLETION_TOKEN));
641
642 Status = gBS->CreateEvent (
643 EVT_NOTIFY_SIGNAL,
644 TPL_CALLBACK,
646 Private,
647 &Private->RxToken.Event
648 );
649
650 if (EFI_ERROR (Status)) {
651 return Status;
652 }
653
654 Private->RxToken.Status = EFI_NOT_READY;
655
656 Status = Private->Ip6->Receive (Private->Ip6, &Private->RxToken);
657 if (EFI_ERROR (Status)) {
658 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status);
659 }
660
661 return Status;
662}
663
671VOID
672EFIAPI
674 IN EFI_EVENT Event,
675 IN VOID *Context
676 )
677{
678 EFI_STATUS Status;
679 PING6_PRIVATE_DATA *Private;
680 PING6_ICMP6_TX_INFO *TxInfo;
681 LIST_ENTRY *Entry;
682 LIST_ENTRY *NextEntry;
683 UINT64 Time;
684
685 Private = (PING6_PRIVATE_DATA *)Context;
686
687 //
688 // Retransmit icmp6 echo request packets per second in sendnumber times.
689 //
690 if (Private->TxCount < Private->SendNum) {
691 Status = Ping6SendEchoRequest (Private);
692 if (Private->TxCount != 0) {
693 if (EFI_ERROR (Status)) {
694 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SEND_REQUEST), gShellNetwork2HiiHandle, Private->TxCount + 1);
695 }
696 }
697 }
698
699 //
700 // Check whether any icmp6 echo request in the list timeout.
701 //
702 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
703 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);
704 Time = Ping6CalculateTick (Private, TxInfo->TimeStamp, Ping6ReadTime (Private));
705
706 //
707 // Remove the timeout echo request from txlist.
708 //
709 if (Time > PING6_DEFAULT_TIMEOUT) {
710 if (EFI_ERROR (TxInfo->Token->Status)) {
711 Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);
712 }
713
714 //
715 // Remove the timeout icmp6 echo request from list.
716 //
717 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_TIMEOUT), gShellNetwork2HiiHandle, TxInfo->SequenceNum);
718
719 RemoveEntryList (&TxInfo->Link);
720 Ping6DestroyTxInfo (TxInfo);
721
722 if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {
723 //
724 // All the left icmp6 echo request in the list timeout.
725 //
726 Private->Status = EFI_TIMEOUT;
727 }
728 }
729 }
730}
731
745 IN PING6_PRIVATE_DATA *Private
746 )
747{
748 EFI_STATUS Status;
749 UINTN HandleIndex;
750 UINTN HandleNum;
751 EFI_HANDLE *HandleBuffer;
752 BOOLEAN UnspecifiedSrc;
753 EFI_STATUS MediaStatus;
756 EFI_IP6_CONFIG_DATA Ip6Config;
758 UINTN IfInfoSize;
759 EFI_IPv6_ADDRESS *Addr;
760 UINTN AddrIndex;
761
762 HandleBuffer = NULL;
763 UnspecifiedSrc = FALSE;
764 MediaStatus = EFI_SUCCESS;
765 Ip6Sb = NULL;
766 IfInfo = NULL;
767 IfInfoSize = 0;
768
769 //
770 // Locate all the handles with ip6 service binding protocol.
771 //
772 Status = gBS->LocateHandleBuffer (
774 &gEfiIp6ServiceBindingProtocolGuid,
775 NULL,
776 &HandleNum,
777 &HandleBuffer
778 );
779 if (EFI_ERROR (Status) || (HandleNum == 0)) {
780 return EFI_ABORTED;
781 }
782
783 if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) {
784 //
785 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
786 //
787 UnspecifiedSrc = TRUE;
788 }
789
790 //
791 // Source address is required when pinging a link-local address.
792 //
793 if (NetIp6IsLinkLocalAddr (&Private->DstAddress) && UnspecifiedSrc) {
794 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), gShellNetwork2HiiHandle);
795 Status = EFI_INVALID_PARAMETER;
796 goto ON_ERROR;
797 }
798
799 //
800 // For each ip6 protocol, check interface addresses list.
801 //
802 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {
803 Ip6Sb = NULL;
804 IfInfo = NULL;
805 IfInfoSize = 0;
806
807 if (UnspecifiedSrc) {
808 //
809 // Check media.
810 //
811 NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);
812 if (MediaStatus != EFI_SUCCESS) {
813 //
814 // Skip this one.
815 //
816 continue;
817 }
818 }
819
820 Status = gBS->HandleProtocol (
821 HandleBuffer[HandleIndex],
822 &gEfiIp6ServiceBindingProtocolGuid,
823 (VOID **)&Ip6Sb
824 );
825 if (EFI_ERROR (Status)) {
826 goto ON_ERROR;
827 }
828
829 //
830 // Ip6config protocol and ip6 service binding protocol are installed
831 // on the same handle.
832 //
833 Status = gBS->HandleProtocol (
834 HandleBuffer[HandleIndex],
835 &gEfiIp6ConfigProtocolGuid,
836 (VOID **)&Ip6Cfg
837 );
838
839 if (EFI_ERROR (Status)) {
840 goto ON_ERROR;
841 }
842
843 //
844 // Get the interface information size.
845 //
846 Status = Ip6Cfg->GetData (
847 Ip6Cfg,
849 &IfInfoSize,
850 NULL
851 );
852
853 if (Status != EFI_BUFFER_TOO_SMALL) {
854 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
855 goto ON_ERROR;
856 }
857
858 IfInfo = AllocateZeroPool (IfInfoSize);
859
860 if (IfInfo == NULL) {
861 Status = EFI_OUT_OF_RESOURCES;
862 goto ON_ERROR;
863 }
864
865 //
866 // Get the interface info.
867 //
868 Status = Ip6Cfg->GetData (
869 Ip6Cfg,
871 &IfInfoSize,
872 IfInfo
873 );
874
875 if (EFI_ERROR (Status)) {
876 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
877 goto ON_ERROR;
878 }
879
880 //
881 // Check whether the source address is one of the interface addresses.
882 //
883 for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) {
884 Addr = &(IfInfo->AddressInfo[AddrIndex].Address);
885
886 if (UnspecifiedSrc) {
887 if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {
888 //
889 // Select the interface automatically.
890 //
891 CopyMem (&Private->SrcAddress, Addr, sizeof (Private->SrcAddress));
892 break;
893 }
894 } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {
895 //
896 // Match a certain interface address.
897 //
898 break;
899 }
900 }
901
902 if (AddrIndex < IfInfo->AddressInfoCount) {
903 //
904 // Found a nic handle with right interface address.
905 //
906 break;
907 }
908
909 FreePool (IfInfo);
910 IfInfo = NULL;
911 }
912
913 //
914 // No exact interface address matched.
915 //
916
917 if (HandleIndex == HandleNum) {
918 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_CONFIGD_NIC_NF), gShellNetwork2HiiHandle);
919 Status = EFI_NOT_FOUND;
920 goto ON_ERROR;
921 }
922
923 Private->NicHandle = HandleBuffer[HandleIndex];
924
925 ASSERT (Ip6Sb != NULL);
926 Status = Ip6Sb->CreateChild (Ip6Sb, &Private->Ip6ChildHandle);
927
928 if (EFI_ERROR (Status)) {
929 goto ON_ERROR;
930 }
931
932 Status = gBS->OpenProtocol (
933 Private->Ip6ChildHandle,
934 &gEfiIp6ProtocolGuid,
935 (VOID **)&Private->Ip6,
936 Private->ImageHandle,
937 Private->Ip6ChildHandle,
938 EFI_OPEN_PROTOCOL_GET_PROTOCOL
939 );
940 if (EFI_ERROR (Status)) {
941 goto ON_ERROR;
942 }
943
944 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));
945
946 //
947 // Configure the ip6 instance for icmp6 packet exchange.
948 //
949 Ip6Config.DefaultProtocol = 58;
950 Ip6Config.AcceptAnyProtocol = FALSE;
951 Ip6Config.AcceptIcmpErrors = TRUE;
952 Ip6Config.AcceptPromiscuous = FALSE;
953 Ip6Config.TrafficClass = 0;
954 Ip6Config.HopLimit = 128;
955 Ip6Config.FlowLabel = 0;
956 Ip6Config.ReceiveTimeout = 0;
957 Ip6Config.TransmitTimeout = 0;
958
959 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);
960
961 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);
962
963 Status = Private->Ip6->Configure (Private->Ip6, &Ip6Config);
964
965 if (EFI_ERROR (Status)) {
966 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_CONFIG), gShellNetwork2HiiHandle, Status);
967 goto ON_ERROR;
968 }
969
970 return EFI_SUCCESS;
971
972ON_ERROR:
973 if (HandleBuffer != NULL) {
974 FreePool (HandleBuffer);
975 }
976
977 if (IfInfo != NULL) {
978 FreePool (IfInfo);
979 }
980
981 if ((Ip6Sb != NULL) && (Private->Ip6ChildHandle != NULL)) {
982 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);
983 }
984
985 return Status;
986}
987
994VOID
996 IN PING6_PRIVATE_DATA *Private
997 )
998{
999 EFI_STATUS Status;
1001
1002 gBS->CloseProtocol (
1003 Private->Ip6ChildHandle,
1004 &gEfiIp6ProtocolGuid,
1005 Private->ImageHandle,
1006 Private->Ip6ChildHandle
1007 );
1008
1009 Status = gBS->HandleProtocol (
1010 Private->NicHandle,
1011 &gEfiIp6ServiceBindingProtocolGuid,
1012 (VOID **)&Ip6Sb
1013 );
1014
1015 if (!EFI_ERROR (Status)) {
1016 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);
1017 }
1018}
1019
1035 IN EFI_HANDLE ImageHandle,
1036 IN UINT32 SendNumber,
1037 IN UINT32 BufferSize,
1038 IN EFI_IPv6_ADDRESS *SrcAddress,
1039 IN EFI_IPv6_ADDRESS *DstAddress
1040 )
1041{
1042 EFI_STATUS Status;
1043 EFI_INPUT_KEY Key;
1044 PING6_PRIVATE_DATA *Private;
1045 PING6_ICMP6_TX_INFO *TxInfo;
1046 LIST_ENTRY *Entry;
1047 LIST_ENTRY *NextEntry;
1048 SHELL_STATUS ShellStatus;
1049
1050 ShellStatus = SHELL_SUCCESS;
1051 Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA));
1052
1053 if (Private == NULL) {
1054 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"Ping6");
1055 ShellStatus = SHELL_OUT_OF_RESOURCES;
1056 goto ON_EXIT;
1057 }
1058
1059 Private->ImageHandle = ImageHandle;
1060 Private->SendNum = SendNumber;
1061 Private->BufferSize = BufferSize;
1062 Private->RttMin = ~((UINT64)(0x0));
1063 Private->Status = EFI_NOT_READY;
1064
1065 InitializeListHead (&Private->TxList);
1066
1067 IP6_COPY_ADDRESS (&Private->SrcAddress, SrcAddress);
1068 IP6_COPY_ADDRESS (&Private->DstAddress, DstAddress);
1069
1070 //
1071 // Open and configure a ip6 instance for ping6.
1072 //
1073 Status = Ping6CreateIpInstance (Private);
1074
1075 if (EFI_ERROR (Status)) {
1076 ShellStatus = SHELL_ACCESS_DENIED;
1077 goto ON_EXIT;
1078 }
1079
1080 //
1081 // Print the command line itself.
1082 //
1083 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_START), gShellNetwork2HiiHandle, mIp6DstString, Private->BufferSize);
1084 //
1085 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1086 //
1087 Status = Ping6OnReceiveEchoReply (Private);
1088
1089 if (EFI_ERROR (Status)) {
1090 ShellStatus = SHELL_ACCESS_DENIED;
1091 goto ON_EXIT;
1092 }
1093
1094 //
1095 // Create and start timer to send icmp6 echo request packet per second.
1096 //
1097 Status = gBS->CreateEvent (
1098 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1099 TPL_CALLBACK,
1101 Private,
1102 &Private->Timer
1103 );
1104
1105 if (EFI_ERROR (Status)) {
1106 ShellStatus = SHELL_ACCESS_DENIED;
1107 goto ON_EXIT;
1108 }
1109
1110 //
1111 // Start a timer to calculate the RTT.
1112 //
1113 Status = Ping6InitRttTimer (Private);
1114 if (EFI_ERROR (Status)) {
1115 ShellStatus = SHELL_ACCESS_DENIED;
1116 goto ON_EXIT;
1117 }
1118
1119 //
1120 // Create a ipv6 token to send the first icmp6 echo request packet.
1121 //
1122 Status = Ping6SendEchoRequest (Private);
1123 //
1124 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1125 //
1126 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
1127 ShellStatus = SHELL_ACCESS_DENIED;
1128 if (Status == EFI_NOT_FOUND) {
1129 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN), gShellNetwork2HiiHandle, mIp6DstString);
1130 }
1131
1132 goto ON_EXIT;
1133 }
1134
1135 Status = gBS->SetTimer (
1136 Private->Timer,
1138 PING6_ONE_SECOND
1139 );
1140
1141 if (EFI_ERROR (Status)) {
1142 ShellStatus = SHELL_ACCESS_DENIED;
1143 goto ON_EXIT;
1144 }
1145
1146 //
1147 // Control the ping6 process by two factors:
1148 // 1. Hot key
1149 // 2. Private->Status
1150 // 2.1. success means all icmp6 echo request packets get reply packets.
1151 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1152 // 2.3. noready means ping6 process is on-the-go.
1153 //
1154 while (Private->Status == EFI_NOT_READY) {
1155 Private->Ip6->Poll (Private->Ip6);
1156
1157 //
1158 // Terminate the ping6 process by 'esc' or 'ctl-c'.
1159 //
1160 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
1161
1162 if (!EFI_ERROR (Status)) {
1163 if ((Key.UnicodeChar == 0x1b) || (Key.UnicodeChar == 0x03) ||
1164 ((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_ESC)))
1165 {
1166 goto ON_STAT;
1167 }
1168 }
1169 }
1170
1171ON_STAT:
1172 //
1173 // Display the statistics in all.
1174 //
1175 gBS->SetTimer (Private->Timer, TimerCancel, 0);
1176
1177 if (Private->TxCount != 0) {
1179 -1,
1180 -1,
1181 NULL,
1182 STRING_TOKEN (STR_PING6_STAT),
1183 gShellNetwork2HiiHandle,
1184 Private->TxCount,
1185 Private->RxCount,
1186 (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,
1187 Private->RttSum
1188 );
1189 }
1190
1191 if (Private->RxCount != 0) {
1193 -1,
1194 -1,
1195 NULL,
1196 STRING_TOKEN (STR_PING6_RTT),
1197 gShellNetwork2HiiHandle,
1198 Private->RttMin,
1199 Private->RttMin + Private->TimerPeriod,
1200 Private->RttMax,
1201 Private->RttMax + Private->TimerPeriod,
1202 DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL),
1203 DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + Private->TimerPeriod
1204 );
1205 }
1206
1207ON_EXIT:
1208
1209 if (Private != NULL) {
1210 Private->Status = EFI_ABORTED;
1211
1212 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
1213 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);
1214
1215 Status = Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);
1216
1217 RemoveEntryList (&TxInfo->Link);
1218 Ping6DestroyTxInfo (TxInfo);
1219 }
1220
1221 Ping6FreeRttTimer (Private);
1222
1223 if (Private->Timer != NULL) {
1224 gBS->CloseEvent (Private->Timer);
1225 }
1226
1227 if (Private->Ip6 != NULL) {
1228 Status = Private->Ip6->Cancel (Private->Ip6, &Private->RxToken);
1229 }
1230
1231 if (Private->RxToken.Event != NULL) {
1232 gBS->CloseEvent (Private->RxToken.Event);
1233 }
1234
1235 if (Private->Ip6ChildHandle != NULL) {
1236 Ping6DestroyIpInstance (Private);
1237 }
1238
1239 FreePool (Private);
1240 }
1241
1242 return ShellStatus;
1243}
1244
1256EFIAPI
1258 IN EFI_HANDLE ImageHandle,
1259 IN EFI_SYSTEM_TABLE *SystemTable
1260 )
1261{
1262 EFI_STATUS Status;
1263 SHELL_STATUS ShellStatus;
1264 EFI_IPv6_ADDRESS DstAddress;
1265 EFI_IPv6_ADDRESS SrcAddress;
1266 UINT64 BufferSize;
1267 UINTN SendNumber;
1268 LIST_ENTRY *ParamPackage;
1269 CONST CHAR16 *ValueStr;
1270 CONST CHAR16 *ValueStrPtr;
1271 UINTN NonOptionCount;
1272 CHAR16 *ProblemParam;
1273
1274 ProblemParam = NULL;
1275 ShellStatus = SHELL_SUCCESS;
1276
1277 Status = ShellCommandLineParseEx (Ping6ParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);
1278 if (EFI_ERROR (Status)) {
1279 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle);
1280 ShellStatus = SHELL_INVALID_PARAMETER;
1281 goto ON_EXIT;
1282 }
1283
1284 SendNumber = 10;
1285 BufferSize = 16;
1286
1287 //
1288 // Parse the parameter of count number.
1289 //
1290 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");
1291 ValueStrPtr = ValueStr;
1292 if (ValueStr != NULL) {
1293 SendNumber = ShellStrToUintn (ValueStrPtr);
1294
1295 //
1296 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1297 //
1298 if ((SendNumber == 0) || (SendNumber > PING6_MAX_SEND_NUMBER)) {
1299 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER), gShellNetwork2HiiHandle, ValueStr);
1300 ShellStatus = SHELL_INVALID_PARAMETER;
1301 goto ON_EXIT;
1302 }
1303 }
1304
1305 //
1306 // Parse the parameter of buffer size.
1307 //
1308 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");
1309 ValueStrPtr = ValueStr;
1310 if (ValueStr != NULL) {
1311 BufferSize = ShellStrToUintn (ValueStrPtr);
1312
1313 //
1314 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1315 //
1316 if ((BufferSize < 16) || (BufferSize > PING6_MAX_BUFFER_SIZE)) {
1317 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE), gShellNetwork2HiiHandle, ValueStr);
1318 ShellStatus = SHELL_INVALID_PARAMETER;
1319 goto ON_EXIT;
1320 }
1321 }
1322
1323 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));
1324 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));
1325
1326 //
1327 // Parse the parameter of source ip address.
1328 //
1329 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");
1330 ValueStrPtr = ValueStr;
1331 if (ValueStr != NULL) {
1332 mIp6SrcString = ValueStr;
1333 Status = NetLibStrToIp6 (ValueStrPtr, &SrcAddress);
1334 if (EFI_ERROR (Status)) {
1335 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr);
1336 ShellStatus = SHELL_INVALID_PARAMETER;
1337 goto ON_EXIT;
1338 }
1339 }
1340
1341 //
1342 // Parse the parameter of destination ip address.
1343 //
1344 NonOptionCount = ShellCommandLineGetCount (ParamPackage);
1345 ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1));
1346 if (NonOptionCount != 2) {
1347 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle);
1348 ShellStatus = SHELL_INVALID_PARAMETER;
1349 goto ON_EXIT;
1350 }
1351
1352 ValueStrPtr = ValueStr;
1353 if (ValueStr != NULL) {
1354 mIp6DstString = ValueStr;
1355 Status = NetLibStrToIp6 (ValueStrPtr, &DstAddress);
1356 if (EFI_ERROR (Status)) {
1357 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr);
1358 ShellStatus = SHELL_INVALID_PARAMETER;
1359 goto ON_EXIT;
1360 }
1361 }
1362
1363 //
1364 // Enter into ping6 process.
1365 //
1366 ShellStatus = ShellPing6 (
1367 ImageHandle,
1368 (UINT32)SendNumber,
1369 (UINT32)BufferSize,
1370 &SrcAddress,
1371 &DstAddress
1372 );
1373
1374ON_EXIT:
1375 ShellCommandLineFreeVarList (ParamPackage);
1376 return ShellStatus;
1377}
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
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)
#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 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
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
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 NetLibStrToIp6(IN CONST CHAR16 *String, OUT EFI_IPv6_ADDRESS *Ip6Address)
Definition: DxeNetLib.c:3154
VOID Ping6DestroyTxInfo(IN PING6_ICMP6_TX_INFO *TxInfo)
Definition: Ping6.c:283
UINT32 Ping6CalculateTick(IN PING6_PRIVATE_DATA *Private, IN UINT32 Begin, IN UINT32 End)
Definition: Ping6.c:263
UINT32 Ping6GetTimerPeriod(VOID)
Definition: Ping6.c:126
VOID Ping6DestroyIpInstance(IN PING6_PRIVATE_DATA *Private)
Definition: Ping6.c:995
EFI_STATUS Ping6OnReceiveEchoReply(IN PING6_PRIVATE_DATA *Private)
Definition: Ping6.c:634
EFI_IP6_COMPLETION_TOKEN * Ping6GenerateToken(IN PING6_PRIVATE_DATA *Private, IN UINT32 TimeStamp, IN UINT16 SequenceNum)
Definition: Ping6.c:495
EFI_STATUS Ping6InitRttTimer(IN PING6_PRIVATE_DATA *Private)
Definition: Ping6.c:184
EFI_STATUS Ping6CreateIpInstance(IN PING6_PRIVATE_DATA *Private)
Definition: Ping6.c:744
VOID Ping6FreeRttTimer(IN PING6_PRIVATE_DATA *Private)
Definition: Ping6.c:227
EFI_STATUS Ping6SendEchoRequest(IN PING6_PRIVATE_DATA *Private)
Definition: Ping6.c:584
SHELL_STATUS ShellPing6(IN EFI_HANDLE ImageHandle, IN UINT32 SendNumber, IN UINT32 BufferSize, IN EFI_IPv6_ADDRESS *SrcAddress, IN EFI_IPv6_ADDRESS *DstAddress)
Definition: Ping6.c:1034
UINT32 Ping6ReadTime(IN PING6_PRIVATE_DATA *Private)
Definition: Ping6.c:245
EFI_STATUS Ping6OnMatchEchoReply(IN PING6_PRIVATE_DATA *Private, IN ICMP6_ECHO_REQUEST_REPLY *Packet)
Definition: Ping6.c:333
SHELL_STATUS EFIAPI ShellCommandRunPing6(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: Ping6.c:1257
VOID EFIAPI Ping6OnEchoReplyReceived6(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping6.c:384
VOID EFIAPI Ping6OnEchoRequestSent6(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping6.c:368
VOID EFIAPI Ping6RttTimerTickRoutine(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping6.c:105
VOID EFIAPI Ping6OnTimerRoutine6(IN EFI_EVENT Event, IN VOID *Context)
Definition: Ping6.c:673
CONST CHAR16 *EFIAPI ShellCommandLineGetValue(IN CONST LIST_ENTRY *CheckPackage, IN CHAR16 *KeyString)
UINTN EFIAPI ShellStrToUintn(IN CONST CHAR16 *String)
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,...)
@ 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_SYSTEM_TABLE * gST
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
UINT32 FragmentLength
Length of fragment data. This field may not be set to zero.
Definition: Ip6.h:415
EFI_IP6_HEADER * Header
Definition: Ip6.h:443
UINT32 DataLength
Definition: Ip6.h:448
EFI_EVENT RecycleSignal
Definition: Ip6.h:432
EFI_IP6_FRAGMENT_DATA FragmentTable[1]
Definition: Ip6.h:456
UINT32 DataLength
Definition: Ip6.h:502
UINT32 ExtHdrsLength
Definition: Ip6.h:487
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
EFI_IPv6_ADDRESS Address
The IPv6 address.
Definition: Ip6.h:221
EFI_STATUS Status
Definition: Ip6.h:536
EFI_EVENT Event
Definition: Ip6.h:522
EFI_IP6_RECEIVE_DATA * RxData
Definition: Ip6.h:541
EFI_IP6_TRANSMIT_DATA * TxData
Definition: Ip6.h:545
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
EFI_IP6_ADDRESS_INFO * AddressInfo
Definition: Ip6Config.h:129
EFI_SIMPLE_TEXT_INPUT_PROTOCOL * ConIn
Definition: UefiSpec.h:2053