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