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