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