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