]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
ShellPkg: Fix ping IPv6 stack usage mode failure issue
[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
85efb9d8 5 Copyright (c) 2009 - 2015, 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
6a5aa4d6 21UINT64 CurrentTick = 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
200 {\r
201 L"-_s",\r
202 TypeValue\r
203 },\r
204 {\r
205 L"-_ip6",\r
206 TypeFlag\r
207 },\r
208 {\r
209 NULL,\r
210 TypeMax\r
211 },\r
212};\r
213\r
214//\r
215// Global Variables in Ping command.\r
216//\r
217STATIC CONST CHAR16 *mDstString;\r
218STATIC CONST CHAR16 *mSrcString;\r
219STATIC UINT64 mFrequency = 0;\r
e0c2cc6f 220EFI_CPU_ARCH_PROTOCOL *gCpu = NULL;\r
221\r
6a5aa4d6 222/**\r
223 Read the current time.\r
224\r
225 @retval the current tick value.\r
226**/\r
e0c2cc6f 227UINT64\r
228EFIAPI\r
229ReadTime (\r
230 VOID\r
231 )\r
232{\r
e0c2cc6f 233 UINT64 TimerPeriod;\r
234 EFI_STATUS Status;\r
235\r
236 ASSERT (gCpu != NULL);\r
237\r
238 Status = gCpu->GetTimerValue (gCpu, 0, &CurrentTick, &TimerPeriod);\r
239 if (EFI_ERROR (Status)) {\r
240 //\r
241 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the\r
242 // TimerPeriod by ourselves.\r
243 //\r
244 CurrentTick += 1000000;\r
245 }\r
246 \r
247 return CurrentTick;\r
248}\r
249\r
68fb0527 250\r
251/**\r
85efb9d8
QS
252 Get and calculate the frequency in ticks/ms.\r
253 The result is saved in the global variable mFrequency\r
68fb0527 254\r
85efb9d8
QS
255 @retval EFI_SUCCESS Calculated the frequency successfully.\r
256 @retval Others Failed to calculate the frequency.\r
68fb0527 257\r
258**/\r
259EFI_STATUS\r
260EFIAPI\r
261GetFrequency (\r
262 VOID\r
263 )\r
264{\r
265 EFI_STATUS Status;\r
68fb0527 266 UINT64 CurrentTick;\r
267 UINT64 TimerPeriod;\r
268\r
e0c2cc6f 269 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &gCpu);\r
68fb0527 270 if (EFI_ERROR (Status)) {\r
271 return Status;\r
272 }\r
273\r
e0c2cc6f 274 Status = gCpu->GetTimerValue (gCpu, 0, &CurrentTick, &TimerPeriod);\r
68fb0527 275\r
276 if (EFI_ERROR (Status)) {\r
277 TimerPeriod = DEFAULT_TIMER_PERIOD;\r
278 }\r
279\r
280 //\r
281 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).\r
85efb9d8 282 // So 1e+12 is divided by timer period to produce the freq in ticks/ms.\r
68fb0527 283 //\r
284 mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
285\r
286 return EFI_SUCCESS;\r
287}\r
288\r
289/**\r
85efb9d8 290 Calculate a duration in ms.\r
68fb0527 291\r
292 @param[in] Begin The start point of time.\r
293 @param[in] End The end point of time.\r
294\r
295 @return The duration in ms.\r
296 @retval 0 The parameters were not valid.\r
297**/\r
298UINT64\r
299EFIAPI\r
300CalculateTick (\r
301 IN UINT64 Begin,\r
302 IN UINT64 End\r
303 )\r
304{\r
305 if (End <= Begin) {\r
306 return (0);\r
307 }\r
308 return DivU64x64Remainder (End - Begin, mFrequency, NULL);\r
309}\r
310\r
311/**\r
312 Destroy PING_ICMPX_TX_INFO, and recollect the memory.\r
313\r
314 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.\r
315 @param[in] IpChoice Whether the token is IPv4 or IPv6\r
316**/\r
317VOID\r
318EFIAPI\r
319PingDestroyTxInfo (\r
320 IN PING_ICMPX_TX_INFO *TxInfo,\r
321 IN UINT32 IpChoice\r
322 )\r
323{\r
324 EFI_IP6_TRANSMIT_DATA *Ip6TxData;\r
325 EFI_IP4_TRANSMIT_DATA *Ip4TxData;\r
326 EFI_IP6_FRAGMENT_DATA *FragData;\r
327 UINTN Index;\r
328\r
329 if (TxInfo == NULL) {\r
330 return;\r
331 }\r
332\r
333 if (TxInfo->Token != NULL) {\r
334\r
335 if (TxInfo->Token->Event != NULL) {\r
336 gBS->CloseEvent (TxInfo->Token->Event);\r
337 }\r
338\r
339 if (TxInfo->Token->Packet.TxData != NULL) {\r
340 if (IpChoice == PING_IP_CHOICE_IP6) {\r
341 Ip6TxData = TxInfo->Token->Packet.TxData;\r
342\r
343 if (Ip6TxData->OverrideData != NULL) {\r
344 FreePool (Ip6TxData->OverrideData);\r
345 }\r
346\r
347 if (Ip6TxData->ExtHdrs != NULL) {\r
348 FreePool (Ip6TxData->ExtHdrs);\r
349 }\r
350\r
351 for (Index = 0; Index < Ip6TxData->FragmentCount; Index++) {\r
352 FragData = Ip6TxData->FragmentTable[Index].FragmentBuffer;\r
353 if (FragData != NULL) {\r
354 FreePool (FragData);\r
355 }\r
356 }\r
357 } else {\r
358 Ip4TxData = TxInfo->Token->Packet.TxData;\r
359\r
360 if (Ip4TxData->OverrideData != NULL) {\r
361 FreePool (Ip4TxData->OverrideData);\r
362 }\r
363\r
364 for (Index = 0; Index < Ip4TxData->FragmentCount; Index++) {\r
365 FragData = Ip4TxData->FragmentTable[Index].FragmentBuffer;\r
366 if (FragData != NULL) {\r
367 FreePool (FragData);\r
368 }\r
369 }\r
370 }\r
371 }\r
372\r
373 FreePool (TxInfo->Token);\r
374 }\r
375\r
376 FreePool (TxInfo);\r
377}\r
378\r
379/**\r
380 Match the request, and reply with SequenceNum/TimeStamp.\r
381\r
382 @param[in] Private The pointer to PING_PRIVATE_DATA.\r
383 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.\r
384\r
385 @retval EFI_SUCCESS The match is successful.\r
386 @retval EFI_NOT_FOUND The reply can't be matched with any request.\r
387\r
388**/\r
389EFI_STATUS\r
390EFIAPI\r
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
566EFIAPI\r
567PingGenerateToken (\r
568 IN PING_PRIVATE_DATA *Private,\r
569 IN UINT64 TimeStamp,\r
570 IN UINT16 SequenceNum\r
571 )\r
572{\r
573 EFI_STATUS Status;\r
574 PING_IPX_COMPLETION_TOKEN *Token;\r
575 VOID *TxData;\r
576 ICMPX_ECHO_REQUEST_REPLY *Request;\r
577 UINT16 HeadSum;\r
578 UINT16 TempChecksum;\r
579\r
580 Request = AllocateZeroPool (Private->BufferSize);\r
581 if (Request == NULL) {\r
582 return NULL;\r
583 }\r
584 TxData = AllocateZeroPool (Private->IpChoice==PING_IP_CHOICE_IP6?sizeof (EFI_IP6_TRANSMIT_DATA):sizeof (EFI_IP4_TRANSMIT_DATA));\r
585 if (TxData == NULL) {\r
586 FreePool (Request);\r
587 return NULL;\r
588 }\r
589 Token = AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN));\r
590 if (Token == NULL) {\r
591 FreePool (Request);\r
592 FreePool (TxData);\r
593 return NULL;\r
594 }\r
595\r
596 //\r
597 // Assembly echo request packet.\r
598 //\r
599 Request->Type = (UINT8)(Private->IpChoice==PING_IP_CHOICE_IP6?ICMP_V6_ECHO_REQUEST:ICMP_V4_ECHO_REQUEST);\r
600 Request->Code = 0;\r
601 Request->SequenceNum = SequenceNum;\r
39a65069 602 Request->TimeStamp = TimeStamp; \r
68fb0527 603 Request->Identifier = 0;\r
604 Request->Checksum = 0;\r
605\r
606 //\r
607 // Assembly token for transmit.\r
608 //\r
609 if (Private->IpChoice==PING_IP_CHOICE_IP6) {\r
610 ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrsLength = 0;\r
611 ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrs = NULL;\r
612 ((EFI_IP6_TRANSMIT_DATA*)TxData)->OverrideData = 0;\r
613 ((EFI_IP6_TRANSMIT_DATA*)TxData)->DataLength = Private->BufferSize;\r
614 ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentCount = 1;\r
615 ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
616 ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;\r
617 } else {\r
618 ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsLength = 0;\r
619 ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsBuffer = NULL;\r
620 ((EFI_IP4_TRANSMIT_DATA*)TxData)->OverrideData = 0;\r
621 ((EFI_IP4_TRANSMIT_DATA*)TxData)->TotalDataLength = Private->BufferSize;\r
622 ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentCount = 1;\r
623 ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
624 ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;\r
625 ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[0] = Private->DstAddress[0];\r
626 ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[1] = Private->DstAddress[1];\r
627 ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[2] = Private->DstAddress[2];\r
628 ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[3] = Private->DstAddress[3];\r
629\r
630 HeadSum = NetChecksum ((UINT8 *) Request, Private->BufferSize);\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
668EFIAPI\r
669PingSendEchoRequest (\r
670 IN PING_PRIVATE_DATA *Private\r
671 )\r
672{\r
673 EFI_STATUS Status;\r
674 PING_ICMPX_TX_INFO *TxInfo;\r
675\r
676 TxInfo = AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO));\r
677\r
678 if (TxInfo == NULL) {\r
679 return EFI_OUT_OF_RESOURCES;\r
680 }\r
681\r
682 TxInfo->TimeStamp = ReadTime ();\r
683 TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
684 TxInfo->Token = PingGenerateToken (\r
685 Private,\r
686 TxInfo->TimeStamp,\r
687 TxInfo->SequenceNum\r
688 );\r
689\r
690 if (TxInfo->Token == NULL) {\r
691 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
692 return EFI_OUT_OF_RESOURCES;\r
693 }\r
694\r
695 ASSERT(Private->ProtocolPointers.Transmit != NULL);\r
696 Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);\r
697\r
698 if (EFI_ERROR (Status)) {\r
699 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
700 return Status;\r
701 }\r
702\r
703 InsertTailList (&Private->TxList, &TxInfo->Link);\r
704 Private->TxCount++;\r
705\r
706 return EFI_SUCCESS;\r
707}\r
708\r
709/**\r
710 Place a completion token into the receive packet queue to receive the echo reply.\r
711\r
712 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
713\r
714 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
715 @retval others Put the token into the receive packet queue unsuccessfully.\r
716\r
717**/\r
718EFI_STATUS\r
719EFIAPI\r
720Ping6ReceiveEchoReply (\r
721 IN PING_PRIVATE_DATA *Private\r
722 )\r
723{\r
724 EFI_STATUS Status;\r
725\r
726 ZeroMem (&Private->RxToken, sizeof (PING_IPX_COMPLETION_TOKEN));\r
727\r
728 Status = gBS->CreateEvent (\r
729 EVT_NOTIFY_SIGNAL,\r
730 TPL_CALLBACK,\r
731 Ping6OnEchoReplyReceived,\r
732 Private,\r
733 &Private->RxToken.Event\r
734 );\r
735\r
736 if (EFI_ERROR (Status)) {\r
737 return Status;\r
738 }\r
739\r
740 Private->RxToken.Status = EFI_NOT_READY;\r
741\r
742 return (Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken));\r
743}\r
744\r
745/**\r
746 Remove the timeout request from the list.\r
747\r
748 @param[in] Event A EFI_EVENT type event.\r
749 @param[in] Context The pointer to Context.\r
750\r
751**/\r
752VOID\r
753EFIAPI\r
754Ping6OnTimerRoutine (\r
755 IN EFI_EVENT Event,\r
756 IN VOID *Context\r
757 )\r
758{\r
759 EFI_STATUS Status;\r
760 PING_PRIVATE_DATA *Private;\r
761 PING_ICMPX_TX_INFO *TxInfo;\r
762 LIST_ENTRY *Entry;\r
763 LIST_ENTRY *NextEntry;\r
764 UINT64 Time;\r
765\r
766 Private = (PING_PRIVATE_DATA *) Context;\r
767 if (Private->Signature != PING_PRIVATE_DATA_SIGNATURE) {\r
768 Private->Status = EFI_NOT_FOUND;\r
769 return;\r
770 }\r
771\r
772 //\r
773 // Retransmit icmp6 echo request packets per second in sendnumber times.\r
774 //\r
775 if (Private->TxCount < Private->SendNum) {\r
776\r
777 Status = PingSendEchoRequest (Private);\r
778 if (Private->TxCount != 0){\r
779 if (EFI_ERROR (Status)) {\r
780 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_SEND_REQUEST), gShellNetwork1HiiHandle, Private->TxCount + 1);\r
781 }\r
782 }\r
783 }\r
784 //\r
785 // Check whether any icmp6 echo request in the list timeout.\r
786 //\r
787 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
788 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
789 Time = CalculateTick (TxInfo->TimeStamp, ReadTime ());\r
790\r
791 //\r
792 // Remove the timeout echo request from txlist.\r
793 //\r
794 if (Time > DEFAULT_TIMEOUT) {\r
795\r
796 if (EFI_ERROR (TxInfo->Token->Status)) {\r
797 Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
798 }\r
799 //\r
800 // Remove the timeout icmp6 echo request from list.\r
801 //\r
802 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_TIMEOUT), gShellNetwork1HiiHandle, TxInfo->SequenceNum);\r
803\r
804 RemoveEntryList (&TxInfo->Link);\r
805 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
806\r
68fb0527 807 if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
808 //\r
809 // All the left icmp6 echo request in the list timeout.\r
810 //\r
811 Private->Status = EFI_TIMEOUT;\r
812 }\r
813 }\r
814 }\r
815}\r
816\r
817/**\r
818 Determine if a IP4 address is Link Local.\r
819\r
820 169.254.1.0 through 169.254.254.255 is link local.\r
821\r
822 @param[in] Address The address to test.\r
823\r
824 @retval TRUE It is.\r
825 @retval FALSE It is not.\r
826**/\r
827BOOLEAN\r
828EFIAPI\r
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
845EFIAPI\r
846PingNetIp4IsUnspecifiedAddr (\r
847 IN CONST EFI_IPv4_ADDRESS *Address\r
848 )\r
849{\r
850 return ((BOOLEAN)((ReadUnaligned32 ((UINT32*)&Address->Addr[0])) == 0x00000000));\r
851}\r
852\r
853/**\r
854 Create a valid IP instance.\r
855\r
856 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
857\r
858 @retval EFI_SUCCESS Create a valid IPx instance successfully.\r
859 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.\r
860 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.\r
861 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
862 @retval EFI_NOT_FOUND The source address is not found.\r
863**/\r
864EFI_STATUS\r
865EFIAPI\r
866PingCreateIpInstance (\r
867 IN PING_PRIVATE_DATA *Private\r
868 )\r
869{\r
870 EFI_STATUS Status;\r
871 UINTN HandleIndex;\r
872 UINTN HandleNum;\r
873 EFI_HANDLE *HandleBuffer;\r
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
884 EfiSb = NULL;\r
885 IpXInterfaceInfo = NULL;\r
886 IfInfoSize = 0;\r
887\r
888 //\r
889 // Locate all the handles with ip6 service binding protocol.\r
890 //\r
891 Status = gBS->LocateHandleBuffer (\r
892 ByProtocol,\r
893 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
894 NULL,\r
895 &HandleNum,\r
896 &HandleBuffer\r
897 );\r
33c031ee 898 if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) {\r
68fb0527 899 return EFI_ABORTED;\r
900 }\r
901 //\r
902 // Source address is required when pinging a link-local address on multi-\r
903 // interfaces host.\r
904 //\r
905 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
906 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS*)&Private->DstAddress) &&\r
907 NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress) &&\r
908 (HandleNum > 1)) {\r
ab7c10f2 909 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", mSrcString); \r
68fb0527 910 Status = EFI_INVALID_PARAMETER;\r
911 goto ON_ERROR;\r
912 }\r
913 } else {\r
914 ASSERT(Private->IpChoice == PING_IP_CHOICE_IP4);\r
915 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS*)&Private->DstAddress) &&\r
916 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress) &&\r
917 (HandleNum > 1)) {\r
ab7c10f2 918 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", mSrcString); \r
68fb0527 919 Status = EFI_INVALID_PARAMETER;\r
920 goto ON_ERROR;\r
921 }\r
922 }\r
923 //\r
924 // For each ip6 protocol, check interface addresses list.\r
925 //\r
926 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
927\r
928 EfiSb = NULL;\r
929 IpXInterfaceInfo = NULL;\r
930 IfInfoSize = 0;\r
931\r
932 Status = gBS->HandleProtocol (\r
933 HandleBuffer[HandleIndex],\r
934 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
935 (VOID **) &EfiSb\r
936 );\r
937 if (EFI_ERROR (Status)) {\r
938 goto ON_ERROR;\r
939 }\r
940\r
941 if (Private->IpChoice == PING_IP_CHOICE_IP6?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress)) {\r
942 //\r
943 // No need to match interface address.\r
944 //\r
945 break;\r
946 } else {\r
947 //\r
948 // Ip6config protocol and ip6 service binding protocol are installed\r
949 // on the same handle.\r
950 //\r
951 Status = gBS->HandleProtocol (\r
952 HandleBuffer[HandleIndex],\r
7c25b7ea 953 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ConfigProtocolGuid:&gEfiIp4Config2ProtocolGuid,\r
68fb0527 954 (VOID **) &IpXCfg\r
955 );\r
956\r
957 if (EFI_ERROR (Status)) {\r
958 goto ON_ERROR;\r
959 }\r
960 //\r
961 // Get the interface information size.\r
962 //\r
963 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
964 Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
965 IpXCfg,\r
966 Ip6ConfigDataTypeInterfaceInfo,\r
967 &IfInfoSize,\r
968 NULL\r
969 );\r
970 } else {\r
7c25b7ea 971 Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData (\r
68fb0527 972 IpXCfg,\r
7c25b7ea 973 Ip4Config2DataTypeInterfaceInfo,\r
68fb0527 974 &IfInfoSize,\r
975 NULL\r
976 );\r
977 }\r
978 \r
979 //\r
980 // Skip the ones not in current use.\r
981 //\r
982 if (Status == EFI_NOT_STARTED) {\r
983 continue;\r
984 }\r
985\r
986 if (Status != EFI_BUFFER_TOO_SMALL) {\r
987 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
988 goto ON_ERROR;\r
989 }\r
990\r
991 IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
992\r
993 if (IpXInterfaceInfo == NULL) {\r
994 Status = EFI_OUT_OF_RESOURCES;\r
995 goto ON_ERROR;\r
996 }\r
997 //\r
998 // Get the interface info.\r
999 //\r
1000 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1001 Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
1002 IpXCfg,\r
1003 Ip6ConfigDataTypeInterfaceInfo,\r
1004 &IfInfoSize,\r
1005 IpXInterfaceInfo\r
1006 );\r
1007 } else {\r
7c25b7ea 1008 Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData (\r
68fb0527 1009 IpXCfg,\r
7c25b7ea 1010 Ip4Config2DataTypeInterfaceInfo,\r
68fb0527 1011 &IfInfoSize,\r
1012 IpXInterfaceInfo\r
1013 );\r
1014 }\r
1015\r
1016 if (EFI_ERROR (Status)) {\r
1017 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
1018 goto ON_ERROR;\r
1019 }\r
1020 //\r
1021 // Check whether the source address is one of the interface addresses.\r
1022 //\r
1023 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1024 for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) {\r
1025\r
1026 Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address);\r
1027 if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
1028 //\r
1029 // Match a certain interface address.\r
1030 //\r
1031 break;\r
1032 }\r
1033 }\r
1034\r
1035 if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) {\r
1036 //\r
1037 // Found a nic handle with right interface address.\r
1038 //\r
1039 break;\r
1040 }\r
1041 } else {\r
1042 //\r
1043 // IP4 address check\r
1044 //\r
7c25b7ea 1045 if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress)) {\r
68fb0527 1046 //\r
1047 // Match a certain interface address.\r
1048 //\r
1049 break;\r
1050 }\r
1051 }\r
1052 }\r
1053\r
1054 FreePool (IpXInterfaceInfo);\r
1055 IpXInterfaceInfo = NULL;\r
1056 }\r
1057 //\r
1058 // No exact interface address matched.\r
1059 //\r
1060\r
1061 if (HandleIndex == HandleNum) {\r
ab7c10f2 1062 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping"); \r
68fb0527 1063 Status = EFI_NOT_FOUND;\r
1064 goto ON_ERROR;\r
1065 }\r
1066\r
1067 Private->NicHandle = HandleBuffer[HandleIndex];\r
1068\r
1069 ASSERT (EfiSb != NULL);\r
1070 Status = EfiSb->CreateChild (EfiSb, &Private->IpChildHandle);\r
1071\r
1072 if (EFI_ERROR (Status)) {\r
1073 goto ON_ERROR;\r
1074 }\r
1075 if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
1076 Status = gBS->OpenProtocol (\r
1077 Private->IpChildHandle,\r
1078 &gEfiIp6ProtocolGuid,\r
1079 &Private->IpProtocol,\r
1080 gImageHandle,\r
1081 Private->IpChildHandle,\r
1082 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1083 );\r
1084 if (EFI_ERROR (Status)) {\r
1085 goto ON_ERROR;\r
1086 }\r
1087\r
1088\r
1089 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
1090\r
1091 //\r
1092 // Configure the ip6 instance for icmp6 packet exchange.\r
1093 //\r
1094 Ip6Config.DefaultProtocol = 58;\r
1095 Ip6Config.AcceptAnyProtocol = FALSE;\r
1096 Ip6Config.AcceptIcmpErrors = TRUE;\r
1097 Ip6Config.AcceptPromiscuous = FALSE;\r
1098 Ip6Config.TrafficClass = 0;\r
1099 Ip6Config.HopLimit = 128;\r
1100 Ip6Config.FlowLabel = 0;\r
1101 Ip6Config.ReceiveTimeout = 0;\r
1102 Ip6Config.TransmitTimeout = 0;\r
1103\r
1104 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
1105 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
1106\r
1107 Status = ((EFI_IP6_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config);\r
1108\r
1109 if (EFI_ERROR (Status)) {\r
1110 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
1111 goto ON_ERROR;\r
1112 }\r
1113\r
1114 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Transmit;\r
1115 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Receive;\r
1116 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Cancel;\r
1117 Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Poll;\r
1118 } else {\r
1119 Status = gBS->OpenProtocol (\r
1120 Private->IpChildHandle,\r
1121 &gEfiIp4ProtocolGuid,\r
1122 &Private->IpProtocol,\r
1123 gImageHandle,\r
1124 Private->IpChildHandle,\r
1125 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1126 );\r
1127 if (EFI_ERROR (Status)) {\r
1128 goto ON_ERROR;\r
1129 }\r
1130\r
1131\r
1132 ZeroMem (&Ip4Config, sizeof (EFI_IP4_CONFIG_DATA));\r
1133\r
1134 //\r
1135 // Configure the ip4 instance for icmp4 packet exchange.\r
1136 //\r
68fb0527 1137 Ip4Config.DefaultProtocol = 1;\r
1138 Ip4Config.AcceptAnyProtocol = FALSE;\r
1139 Ip4Config.AcceptBroadcast = FALSE;\r
1140 Ip4Config.AcceptIcmpErrors = TRUE;\r
1141 Ip4Config.AcceptPromiscuous = FALSE;\r
1142 Ip4Config.DoNotFragment = FALSE;\r
1143 Ip4Config.RawData = FALSE;\r
1144 Ip4Config.ReceiveTimeout = 0;\r
1145 Ip4Config.TransmitTimeout = 0;\r
1146 Ip4Config.UseDefaultAddress = TRUE;\r
1147 Ip4Config.TimeToLive = 128;\r
1148 Ip4Config.TypeOfService = 0;\r
1149\r
1150 Status = ((EFI_IP4_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config);\r
1151\r
1152 if (EFI_ERROR (Status)) {\r
1153 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
1154 goto ON_ERROR;\r
1155 }\r
1156\r
1157 Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Transmit;\r
1158 Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Receive;\r
1159 Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Cancel;\r
1160 Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Poll; \r
1161 }\r
1162\r
1163 if (HandleBuffer != NULL) {\r
1164 FreePool (HandleBuffer);\r
1165 }\r
1166\r
1167 return EFI_SUCCESS;\r
1168\r
1169ON_ERROR:\r
1170 if (HandleBuffer != NULL) {\r
1171 FreePool (HandleBuffer);\r
1172 }\r
1173\r
1174 if (IpXInterfaceInfo != NULL) {\r
1175 FreePool (IpXInterfaceInfo);\r
1176 }\r
1177\r
1178 if ((EfiSb != NULL) && (Private->IpChildHandle != NULL)) {\r
1179 EfiSb->DestroyChild (EfiSb, Private->IpChildHandle);\r
1180 }\r
1181\r
1182 return Status;\r
1183}\r
1184\r
1185/**\r
75dce340 1186 Destroy the IP instance.\r
68fb0527 1187\r
1188 @param[in] Private The pointer of PING_PRIVATE_DATA.\r
1189\r
1190**/\r
1191VOID\r
1192EFIAPI\r
75dce340 1193Ping6DestroyIp6Instance (\r
68fb0527 1194 IN PING_PRIVATE_DATA *Private\r
1195 )\r
1196{\r
1197 EFI_STATUS Status;\r
1198 EFI_SERVICE_BINDING_PROTOCOL *IpSb;\r
1199\r
1200 gBS->CloseProtocol (\r
1201 Private->IpChildHandle,\r
1202 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ProtocolGuid:&gEfiIp4ProtocolGuid,\r
1203 gImageHandle,\r
1204 Private->IpChildHandle\r
1205 );\r
1206\r
1207 Status = gBS->HandleProtocol (\r
1208 Private->NicHandle,\r
1209 Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
1210 (VOID **) &IpSb\r
1211 );\r
1212\r
1213 if (!EFI_ERROR(Status)) {\r
1214 IpSb->DestroyChild (IpSb, Private->IpChildHandle);\r
1215 }\r
1216}\r
1217\r
1218/**\r
1219 The Ping Process.\r
1220\r
1221 @param[in] SendNumber The send request count.\r
1222 @param[in] BufferSize The send buffer size.\r
1223 @param[in] SrcAddress The source address.\r
1224 @param[in] DstAddress The destination address.\r
1225 @param[in] IpChoice The choice between IPv4 and IPv6.\r
1226\r
1227 @retval SHELL_SUCCESS The ping processed successfullly.\r
1228 @retval others The ping processed unsuccessfully.\r
1229**/\r
1230SHELL_STATUS\r
1231EFIAPI\r
1232ShellPing (\r
1233 IN UINT32 SendNumber,\r
1234 IN UINT32 BufferSize,\r
1235 IN EFI_IPv6_ADDRESS *SrcAddress,\r
1236 IN EFI_IPv6_ADDRESS *DstAddress,\r
1237 IN UINT32 IpChoice\r
1238 )\r
1239{\r
1240 EFI_STATUS Status;\r
1241 PING_PRIVATE_DATA *Private;\r
1242 PING_ICMPX_TX_INFO *TxInfo;\r
1243 LIST_ENTRY *Entry;\r
1244 LIST_ENTRY *NextEntry;\r
1245 SHELL_STATUS ShellStatus;\r
1246\r
1247 ShellStatus = SHELL_SUCCESS;\r
1248 Private = AllocateZeroPool (sizeof (PING_PRIVATE_DATA));\r
1249\r
1250 if (Private == NULL) {\r
1251 return (SHELL_OUT_OF_RESOURCES);\r
1252 }\r
1253\r
1254 Private->IpChoice = IpChoice;\r
1255 Private->Signature = PING_PRIVATE_DATA_SIGNATURE;\r
1256 Private->SendNum = SendNumber;\r
1257 Private->BufferSize = BufferSize;\r
1258 Private->RttMin = ~((UINT64 )(0x0));\r
1259 Private->Status = EFI_NOT_READY;\r
1260\r
1261 CopyMem(&Private->SrcAddress, SrcAddress, sizeof(Private->SrcAddress));\r
1262 CopyMem(&Private->DstAddress, DstAddress, sizeof(Private->DstAddress));\r
1263\r
1264 InitializeListHead (&Private->TxList);\r
1265\r
1266 //\r
1267 // Open and configure a ip instance for us.\r
1268 //\r
1269 Status = PingCreateIpInstance (Private);\r
1270\r
1271 if (EFI_ERROR (Status)) {\r
1272 ShellStatus = SHELL_ACCESS_DENIED;\r
1273 goto ON_EXIT;\r
1274 }\r
1275 //\r
1276 // Print the command line itself.\r
1277 //\r
1278 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_START), gShellNetwork1HiiHandle, mDstString, Private->BufferSize);\r
1279 //\r
1280 // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
1281 //\r
1282 Status = Ping6ReceiveEchoReply (Private);\r
1283\r
1284 if (EFI_ERROR (Status)) {\r
1285 ShellStatus = SHELL_ACCESS_DENIED;\r
1286 goto ON_EXIT;\r
1287 }\r
1288 //\r
1289 // Create and start timer to send icmp6 echo request packet per second.\r
1290 //\r
1291 Status = gBS->CreateEvent (\r
1292 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1293 TPL_CALLBACK,\r
1294 Ping6OnTimerRoutine,\r
1295 Private,\r
1296 &Private->Timer\r
1297 );\r
1298\r
1299 if (EFI_ERROR (Status)) {\r
1300 ShellStatus = SHELL_ACCESS_DENIED;\r
1301 goto ON_EXIT;\r
1302 }\r
1303 //\r
1304 // Create a ipv6 token to send the first icmp6 echo request packet.\r
1305 //\r
1306 Status = PingSendEchoRequest (Private);\r
1307 //\r
1308 // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
1309 //\r
1310 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
1311 ShellStatus = SHELL_ACCESS_DENIED;\r
1312 if(Status == EFI_NOT_FOUND) {\r
1313 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOSOURCE_INDO), gShellNetwork1HiiHandle, mDstString);\r
1314 } else if (Status == RETURN_NO_MAPPING) {\r
1315 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString);\r
1316 } else {\r
ab7c10f2 1317 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, L"ping", Status); \r
68fb0527 1318 }\r
1319\r
1320 goto ON_EXIT;\r
1321 }\r
1322\r
1323 Status = gBS->SetTimer (\r
1324 Private->Timer,\r
1325 TimerPeriodic,\r
1326 ONE_SECOND\r
1327 );\r
1328\r
1329 if (EFI_ERROR (Status)) {\r
1330 ShellStatus = SHELL_ACCESS_DENIED;\r
1331 goto ON_EXIT;\r
1332 }\r
1333 //\r
1334 // Control the ping6 process by two factors:\r
1335 // 1. Hot key\r
1336 // 2. Private->Status\r
1337 // 2.1. success means all icmp6 echo request packets get reply packets.\r
1338 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
1339 // 2.3. noready means ping6 process is on-the-go.\r
1340 //\r
1341 while (Private->Status == EFI_NOT_READY) {\r
1342 Status = Private->ProtocolPointers.Poll (Private->IpProtocol);\r
1343 if (ShellGetExecutionBreakFlag()) {\r
1344 Private->Status = EFI_ABORTED;\r
1345 goto ON_STAT;\r
1346 }\r
1347 }\r
1348\r
1349ON_STAT:\r
1350 //\r
1351 // Display the statistics in all.\r
1352 //\r
1353 gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
1354\r
1355 if (Private->TxCount != 0) {\r
1356 ShellPrintHiiEx (\r
1357 -1,\r
1358 -1,\r
1359 NULL,\r
1360 STRING_TOKEN (STR_PING_STAT),\r
1361 gShellNetwork1HiiHandle,\r
1362 Private->TxCount,\r
1363 Private->RxCount,\r
1364 (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,\r
1365 Private->RttSum\r
1366 );\r
1367 }\r
1368\r
1369 if (Private->RxCount != 0) {\r
1370 ShellPrintHiiEx (\r
1371 -1,\r
1372 -1,\r
1373 NULL,\r
1374 STRING_TOKEN (STR_PING_RTT),\r
1375 gShellNetwork1HiiHandle,\r
1376 Private->RttMin,\r
1377 Private->RttMax,\r
1378 DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL)\r
1379 );\r
1380 }\r
1381\r
1382ON_EXIT:\r
1383\r
1384 if (Private != NULL) {\r
1385\r
1386 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
1387 TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
1388\r
1389 if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) {\r
1390 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
1391 }\r
1392\r
1393 RemoveEntryList (&TxInfo->Link);\r
1394 PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
1395 }\r
1396\r
1397 if (Private->Timer != NULL) {\r
1398 gBS->CloseEvent (Private->Timer);\r
1399 }\r
1400\r
1401 if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) {\r
1402 Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, &Private->RxToken);\r
1403 }\r
1404\r
1405 if (Private->RxToken.Event != NULL) {\r
1406 gBS->CloseEvent (Private->RxToken.Event);\r
1407 }\r
1408\r
1409 if (Private->IpChildHandle != NULL) {\r
75dce340 1410 Ping6DestroyIp6Instance (Private);\r
68fb0527 1411 }\r
1412\r
1413 FreePool (Private);\r
1414 }\r
1415\r
1416 return ShellStatus;\r
1417}\r
1418\r
1419/**\r
1420 Function for 'ping' command.\r
1421\r
1422 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
1423 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
7c25b7ea 1424\r
1425 @retval SHELL_SUCCESS The ping processed successfullly.\r
1426 @retval others The ping processed unsuccessfully.\r
1427 \r
68fb0527 1428**/\r
1429SHELL_STATUS\r
1430EFIAPI\r
1431ShellCommandRunPing (\r
1432 IN EFI_HANDLE ImageHandle,\r
1433 IN EFI_SYSTEM_TABLE *SystemTable\r
1434 )\r
1435{\r
1436 EFI_STATUS Status;\r
1437 SHELL_STATUS ShellStatus;\r
1438 EFI_IPv6_ADDRESS DstAddress;\r
1439 EFI_IPv6_ADDRESS SrcAddress;\r
1440 UINT64 BufferSize;\r
1441 UINTN SendNumber;\r
1442 LIST_ENTRY *ParamPackage;\r
1443 CONST CHAR16 *ValueStr;\r
1444 UINTN NonOptionCount;\r
1445 UINT32 IpChoice;\r
ab7c10f2 1446 CHAR16 *ProblemParam;\r
68fb0527 1447\r
1448 //\r
1449 // we use IPv6 buffers to hold items... \r
1450 // make sure this is enough space!\r
1451 //\r
1452 ASSERT(sizeof(EFI_IPv4_ADDRESS ) <= sizeof(EFI_IPv6_ADDRESS ));\r
1453 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN) <= sizeof(EFI_IP6_COMPLETION_TOKEN ));\r
1454\r
1455 IpChoice = PING_IP_CHOICE_IP4;\r
1456\r
1457 ShellStatus = SHELL_SUCCESS;\r
ab7c10f2 1458 ProblemParam = NULL;\r
68fb0527 1459\r
ab7c10f2 1460 Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);\r
68fb0527 1461 if (EFI_ERROR(Status)) {\r
ab7c10f2 1462 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);\r
68fb0527 1463 ShellStatus = SHELL_INVALID_PARAMETER;\r
1464 goto ON_EXIT;\r
1465 }\r
1466\r
1467 if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) {\r
1468 IpChoice = PING_IP_CHOICE_IP6;\r
1469 }\r
1470\r
1471 //\r
1472 // Parse the paramter of count number.\r
1473 //\r
1474 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
1475 if (ValueStr != NULL) {\r
1476 SendNumber = ShellStrToUintn (ValueStr);\r
1477\r
1478 //\r
1479 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1480 //\r
1481 if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) {\r
ab7c10f2 1482 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); \r
68fb0527 1483 ShellStatus = SHELL_INVALID_PARAMETER;\r
1484 goto ON_EXIT;\r
1485 }\r
1486 } else {\r
1487 SendNumber = DEFAULT_SEND_COUNT;\r
1488 }\r
1489 //\r
1490 // Parse the paramter of buffer size.\r
1491 //\r
1492 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
1493 if (ValueStr != NULL) {\r
1494 BufferSize = ShellStrToUintn (ValueStr);\r
1495\r
1496 //\r
1497 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1498 //\r
1499 if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) {\r
ab7c10f2 1500 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); \r
68fb0527 1501 ShellStatus = SHELL_INVALID_PARAMETER;\r
1502 goto ON_EXIT;\r
1503 }\r
1504 } else {\r
1505 BufferSize = DEFAULT_BUFFER_SIZE;\r
1506 }\r
1507\r
1508 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
1509 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
1510\r
1511 //\r
1512 // Parse the paramter of source ip address.\r
1513 //\r
1514 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s");\r
1515 if (ValueStr != NULL) {\r
1516 mSrcString = ValueStr;\r
1517 if (IpChoice == PING_IP_CHOICE_IP6) {\r
1518 Status = NetLibStrToIp6 (ValueStr, &SrcAddress);\r
1519 } else {\r
1520 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&SrcAddress);\r
1521 }\r
1522 if (EFI_ERROR (Status)) {\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 }\r
1528 //\r
1529 // Parse the paramter of destination ip address.\r
1530 //\r
1531 NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
1532 if (NonOptionCount < 2) {\r
ab7c10f2 1533 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping"); \r
68fb0527 1534 ShellStatus = SHELL_INVALID_PARAMETER;\r
1535 goto ON_EXIT;\r
1536 }\r
1537 if (NonOptionCount > 2) {\r
ab7c10f2 1538 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping"); \r
68fb0527 1539 ShellStatus = SHELL_INVALID_PARAMETER;\r
1540 goto ON_EXIT;\r
1541 }\r
1542 ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);\r
1543 if (ValueStr != NULL) {\r
1544 mDstString = ValueStr;\r
1545 if (IpChoice == PING_IP_CHOICE_IP6) {\r
1546 Status = NetLibStrToIp6 (ValueStr, &DstAddress);\r
1547 } else {\r
1548 Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&DstAddress);\r
1549 }\r
1550 if (EFI_ERROR (Status)) {\r
ab7c10f2 1551 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); \r
68fb0527 1552 ShellStatus = SHELL_INVALID_PARAMETER;\r
1553 goto ON_EXIT;\r
1554 }\r
1555 }\r
1556 //\r
1557 // Get frequency to calculate the time from ticks.\r
1558 //\r
1559 Status = GetFrequency ();\r
1560\r
1561 if (EFI_ERROR(Status)) {\r
1562 goto ON_EXIT;\r
1563 }\r
1564 //\r
1565 // Enter into ping process.\r
1566 //\r
1567 ShellStatus = ShellPing (\r
1568 (UINT32)SendNumber,\r
1569 (UINT32)BufferSize,\r
1570 &SrcAddress,\r
1571 &DstAddress,\r
1572 IpChoice\r
1573 );\r
1574\r
1575ON_EXIT:\r
1576 ShellCommandLineFreeVarList (ParamPackage);\r
1577 return ShellStatus;\r
1578}\r