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