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