]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Application/Ping6/Ping6.c
NetworkPkg: Support print help information using -? command.
[mirror_edk2.git] / NetworkPkg / Application / Ping6 / Ping6.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 The implementation for Ping6 application.\r
3\r
be6cd654 4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
a3bcde70
HT
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 <Library/ShellLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/BaseLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/DebugLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
be6cd654 22#include <Library/UefiHiiServicesLib.h>\r
a3bcde70
HT
23#include <Library/HiiLib.h>\r
24#include <Library/NetLib.h>\r
25\r
26#include <Protocol/Cpu.h>\r
27#include <Protocol/ServiceBinding.h>\r
28#include <Protocol/Ip6.h>\r
29#include <Protocol/Ip6Config.h>\r
30\r
31#include "Ping6.h"\r
32\r
33SHELL_PARAM_ITEM Ping6ParamList[] = {\r
34 {\r
35 L"-l",\r
36 TypeValue\r
37 },\r
38 {\r
39 L"-n",\r
40 TypeValue\r
41 },\r
42 {\r
43 L"-s",\r
44 TypeValue\r
45 },\r
a3bcde70
HT
46 {\r
47 NULL,\r
48 TypeMax\r
49 },\r
50};\r
51\r
52//\r
53// Global Variables in Ping6 application.\r
54//\r
55EFI_HII_HANDLE mHiiHandle;\r
56CONST CHAR16 *mIp6DstString;\r
57CONST CHAR16 *mIp6SrcString;\r
cda10fe4 58UINT64 mFrequency = 0;\r
a3bcde70 59/**\r
5edac28e 60 Get and calculate the frequency in tick/ms.\r
a3bcde70
HT
61 The result is saved in the globle variable mFrequency\r
62\r
5edac28e
SQ
63 @retval EFI_SUCCESS Calculated the frequency successfully.\r
64 @retval Others Failed to calculate the frequency.\r
a3bcde70
HT
65\r
66**/\r
67EFI_STATUS\r
68Ping6GetFrequency (\r
69 VOID\r
70 )\r
71{\r
72 EFI_STATUS Status;\r
73 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
74 UINT64 CurrentTick;\r
cda10fe4 75 UINT64 TimerPeriod;\r
a3bcde70
HT
76\r
77 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);\r
78\r
79 if (EFI_ERROR (Status)) {\r
80 return Status;\r
81 }\r
82\r
cda10fe4 83 Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod);\r
a3bcde70
HT
84\r
85 if (EFI_ERROR (Status)) {\r
86 //\r
87 // For NT32 Simulator only. 358049 is a similar value to keep timer granularity.\r
88 // Set the timer period by ourselves.\r
89 //\r
cda10fe4 90 TimerPeriod = (UINT64) NTTIMERPERIOD;\r
a3bcde70
HT
91 }\r
92 //\r
93 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).\r
94 // So 1e+12 is divided by timer period to produce the freq in tick/ms.\r
95 //\r
cda10fe4 96 mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
a3bcde70
HT
97\r
98 return EFI_SUCCESS;\r
99}\r
100\r
101/**\r
5edac28e 102 Get and calculate the duration in ms.\r
a3bcde70
HT
103\r
104 @param[in] Begin The start point of time.\r
105 @param[in] End The end point of time.\r
106\r
107 @return The duration in ms.\r
108\r
109**/\r
cda10fe4 110UINT64\r
a3bcde70
HT
111Ping6CalculateTick (\r
112 IN UINT64 Begin,\r
113 IN UINT64 End\r
114 )\r
115{\r
116 ASSERT (End > Begin);\r
cda10fe4 117 return DivU64x64Remainder (End - Begin, mFrequency, NULL);\r
a3bcde70
HT
118}\r
119\r
120/**\r
121 Destroy IPING6_ICMP6_TX_INFO, and recollect the memory.\r
122\r
123 @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO.\r
124\r
125**/\r
126VOID\r
127Ping6DestroyTxInfo (\r
128 IN PING6_ICMP6_TX_INFO *TxInfo\r
129 )\r
130{\r
131 EFI_IP6_TRANSMIT_DATA *TxData;\r
132 EFI_IP6_FRAGMENT_DATA *FragData;\r
133 UINTN Index;\r
134\r
135 ASSERT (TxInfo != NULL);\r
136\r
137 if (TxInfo->Token != NULL) {\r
138\r
139 if (TxInfo->Token->Event != NULL) {\r
140 gBS->CloseEvent (TxInfo->Token->Event);\r
141 }\r
142\r
143 TxData = TxInfo->Token->Packet.TxData;\r
144 if (TxData != NULL) {\r
145\r
146 if (TxData->OverrideData != NULL) {\r
147 FreePool (TxData->OverrideData);\r
148 }\r
149\r
150 if (TxData->ExtHdrs != NULL) {\r
151 FreePool (TxData->ExtHdrs);\r
152 }\r
153\r
154 for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
155 FragData = TxData->FragmentTable[Index].FragmentBuffer;\r
156 if (FragData != NULL) {\r
157 FreePool (FragData);\r
158 }\r
159 }\r
160 }\r
161\r
162 FreePool (TxInfo->Token);\r
163 }\r
164\r
165 FreePool (TxInfo);\r
166}\r
167\r
168/**\r
169 Match the request, and reply with SequenceNum/TimeStamp.\r
170\r
171 @param[in] Private The pointer to PING6_PRIVATE_DATA.\r
172 @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY.\r
173\r
174 @retval EFI_SUCCESS The match is successful.\r
175 @retval EFI_NOT_FOUND The reply can't be matched with any request.\r
176\r
177**/\r
178EFI_STATUS\r
179Ping6MatchEchoReply (\r
180 IN PING6_PRIVATE_DATA *Private,\r
181 IN ICMP6_ECHO_REQUEST_REPLY *Packet\r
182 )\r
183{\r
184 PING6_ICMP6_TX_INFO *TxInfo;\r
185 LIST_ENTRY *Entry;\r
186 LIST_ENTRY *NextEntry;\r
187\r
188 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
189 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
190\r
191 if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) {\r
192 Private->RxCount++;\r
193 RemoveEntryList (&TxInfo->Link);\r
194 Ping6DestroyTxInfo (TxInfo);\r
195 return EFI_SUCCESS;\r
196 }\r
197 }\r
198\r
199 return EFI_NOT_FOUND;\r
200}\r
201\r
202/**\r
203 The original intention is to send a request.\r
204 Currently, the application retransmits an icmp6 echo request packet\r
205 per second in sendnumber times that is specified by the user.\r
206 Because nothing can be done here, all things move to the timer rountine.\r
207\r
208 @param[in] Event A EFI_EVENT type event.\r
209 @param[in] Context The pointer to Context.\r
210\r
211**/\r
212VOID\r
213EFIAPI\r
214Ping6OnEchoRequestSent (\r
215 IN EFI_EVENT Event,\r
216 IN VOID *Context\r
217 )\r
218{\r
219}\r
220\r
221/**\r
222 receive reply, match and print reply infomation.\r
223\r
224 @param[in] Event A EFI_EVENT type event.\r
225 @param[in] Context The pointer to context.\r
226\r
227**/\r
228VOID\r
229EFIAPI\r
230Ping6OnEchoReplyReceived (\r
231 IN EFI_EVENT Event,\r
232 IN VOID *Context\r
233 )\r
234{\r
235 EFI_STATUS Status;\r
236 PING6_PRIVATE_DATA *Private;\r
237 EFI_IP6_COMPLETION_TOKEN *RxToken;\r
238 EFI_IP6_RECEIVE_DATA *RxData;\r
239 ICMP6_ECHO_REQUEST_REPLY *Reply;\r
240 UINT32 PayLoad;\r
cda10fe4 241 UINT64 Rtt;\r
a3bcde70
HT
242 CHAR8 Near;\r
243\r
244 Private = (PING6_PRIVATE_DATA *) Context;\r
245\r
246 if (Private->Status == EFI_ABORTED) {\r
247 return;\r
248 }\r
249\r
250 RxToken = &Private->RxToken;\r
251 RxData = RxToken->Packet.RxData;\r
252 Reply = RxData->FragmentTable[0].FragmentBuffer;\r
253 PayLoad = RxData->DataLength;\r
254\r
255 if (RxData->Header->NextHeader != IP6_ICMP) {\r
256 goto ON_EXIT;\r
257 }\r
258\r
259 if (!IP6_IS_MULTICAST (&Private->DstAddress) && \r
260 !EFI_IP6_EQUAL (&RxData->Header->SourceAddress, &Private->DstAddress)) {\r
261 goto ON_EXIT;\r
262 }\r
263\r
264 if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) {\r
265 goto ON_EXIT;\r
266 }\r
267\r
268 if (PayLoad != Private->BufferSize) {\r
269 goto ON_EXIT;\r
270 }\r
271 //\r
272 // Check whether the reply matches the sent request before.\r
273 //\r
274 Status = Ping6MatchEchoReply (Private, Reply);\r
275 if (EFI_ERROR(Status)) {\r
276 goto ON_EXIT;\r
277 }\r
278 //\r
279 // Display statistics on this icmp6 echo reply packet.\r
280 //\r
281 Rtt = Ping6CalculateTick (Reply->TimeStamp, ReadTime ());\r
282 if (Rtt != 0) {\r
283 Near = (CHAR8) '=';\r
284 } else {\r
285 Near = (CHAR8) '<';\r
286 }\r
287\r
288 Private->RttSum += Rtt;\r
289 Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
290 Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax;\r
291\r
292 ShellPrintHiiEx (\r
293 -1,\r
294 -1,\r
295 NULL,\r
296 STRING_TOKEN (STR_PING6_REPLY_INFO),\r
297 mHiiHandle,\r
298 PayLoad,\r
299 mIp6DstString,\r
300 Reply->SequenceNum,\r
301 RxData->Header->HopLimit,\r
302 Near,\r
303 Rtt\r
304 );\r
305\r
306ON_EXIT:\r
307\r
308 if (Private->RxCount < Private->SendNum) {\r
309 //\r
310 // Continue to receive icmp6 echo reply packets.\r
311 //\r
312 RxToken->Status = EFI_ABORTED;\r
313\r
314 Status = Private->Ip6->Receive (Private->Ip6, RxToken);\r
315\r
316 if (EFI_ERROR (Status)) {\r
317 Private->Status = EFI_ABORTED;\r
318 }\r
319 } else {\r
320 //\r
321 // All reply have already been received from the dest host.\r
322 //\r
323 Private->Status = EFI_SUCCESS;\r
324 }\r
325 //\r
326 // Singal to recycle the each rxdata here, not at the end of process.\r
327 //\r
328 gBS->SignalEvent (RxData->RecycleSignal);\r
329}\r
330\r
331/**\r
332 Initial EFI_IP6_COMPLETION_TOKEN.\r
333\r
334 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
335 @param[in] TimeStamp The TimeStamp of request.\r
336 @param[in] SequenceNum The SequenceNum of request.\r
337\r
338 @return The pointer of EFI_IP6_COMPLETION_TOKEN.\r
339\r
340**/\r
341EFI_IP6_COMPLETION_TOKEN *\r
342Ping6GenerateToken (\r
343 IN PING6_PRIVATE_DATA *Private,\r
344 IN UINT64 TimeStamp,\r
345 IN UINT16 SequenceNum\r
346 )\r
347{\r
348 EFI_STATUS Status;\r
349 EFI_IP6_COMPLETION_TOKEN *Token;\r
350 EFI_IP6_TRANSMIT_DATA *TxData;\r
351 ICMP6_ECHO_REQUEST_REPLY *Request;\r
352\r
353 Request = AllocateZeroPool (Private->BufferSize);\r
354\r
355 if (Request == NULL) {\r
356 return NULL;\r
357 }\r
358 //\r
359 // Assembly icmp6 echo request packet.\r
360 //\r
361 Request->Type = ICMP_V6_ECHO_REQUEST;\r
362 Request->Code = 0;\r
363 Request->SequenceNum = SequenceNum;\r
364 Request->TimeStamp = TimeStamp;\r
365 Request->Identifier = 0;\r
366 //\r
367 // Leave check sum to ip6 layer, since it has no idea of source address\r
368 // selection.\r
369 //\r
370 Request->Checksum = 0;\r
371\r
372 TxData = AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA));\r
373\r
374 if (TxData == NULL) {\r
375 FreePool (Request);\r
376 return NULL;\r
377 }\r
378 //\r
379 // Assembly ipv6 token for transmit.\r
380 //\r
381 TxData->OverrideData = 0;\r
382 TxData->ExtHdrsLength = 0;\r
383 TxData->ExtHdrs = NULL;\r
384 TxData->DataLength = Private->BufferSize;\r
385 TxData->FragmentCount = 1;\r
386 TxData->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
387 TxData->FragmentTable[0].FragmentLength = Private->BufferSize;\r
388\r
389 Token = AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN));\r
390\r
391 if (Token == NULL) {\r
392 FreePool (Request);\r
393 FreePool (TxData);\r
394 return NULL;\r
395 }\r
396\r
397 Token->Status = EFI_ABORTED;\r
398 Token->Packet.TxData = TxData;\r
399\r
400 Status = gBS->CreateEvent (\r
401 EVT_NOTIFY_SIGNAL,\r
402 TPL_CALLBACK,\r
403 Ping6OnEchoRequestSent,\r
404 Private,\r
405 &Token->Event\r
406 );\r
407\r
408 if (EFI_ERROR (Status)) {\r
409 FreePool (Request);\r
410 FreePool (TxData);\r
411 FreePool (Token);\r
412 return NULL;\r
413 }\r
414\r
415 return Token;\r
416}\r
417\r
418/**\r
419 Transmit the EFI_IP6_COMPLETION_TOKEN.\r
420\r
421 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
422\r
423 @retval EFI_SUCCESS Transmitted successfully.\r
424 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
425 @retval others Transmitted unsuccessfully.\r
426\r
427**/\r
428EFI_STATUS\r
429Ping6SendEchoRequest (\r
430 IN PING6_PRIVATE_DATA *Private\r
431 )\r
432{\r
433 EFI_STATUS Status;\r
434 PING6_ICMP6_TX_INFO *TxInfo;\r
435\r
436 TxInfo = AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO));\r
437\r
438 if (TxInfo == NULL) {\r
439 return EFI_OUT_OF_RESOURCES;\r
440 }\r
441\r
442 TxInfo->TimeStamp = ReadTime ();\r
443 TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
444\r
445 TxInfo->Token = Ping6GenerateToken (\r
446 Private,\r
447 TxInfo->TimeStamp,\r
448 TxInfo->SequenceNum\r
449 );\r
450\r
451 if (TxInfo->Token == NULL) {\r
452 Ping6DestroyTxInfo (TxInfo);\r
453 return EFI_OUT_OF_RESOURCES;\r
454 }\r
455\r
456 Status = Private->Ip6->Transmit (Private->Ip6, TxInfo->Token);\r
457\r
458 if (EFI_ERROR (Status)) {\r
459 Ping6DestroyTxInfo (TxInfo);\r
460 return Status;\r
461 }\r
462\r
463 InsertTailList (&Private->TxList, &TxInfo->Link);\r
464 Private->TxCount++;\r
465\r
466 return EFI_SUCCESS;\r
467}\r
468\r
469/**\r
470 Place a completion token into the receive packet queue to receive the echo reply.\r
471\r
472 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
473\r
474 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
475 @retval others Put the token into the receive packet queue unsuccessfully.\r
476\r
477**/\r
478EFI_STATUS\r
479Ping6ReceiveEchoReply (\r
480 IN PING6_PRIVATE_DATA *Private\r
481 )\r
482{\r
483 EFI_STATUS Status;\r
484\r
485 ZeroMem (&Private->RxToken, sizeof (EFI_IP6_COMPLETION_TOKEN));\r
486\r
487 Status = gBS->CreateEvent (\r
488 EVT_NOTIFY_SIGNAL,\r
489 TPL_CALLBACK,\r
490 Ping6OnEchoReplyReceived,\r
491 Private,\r
492 &Private->RxToken.Event\r
493 );\r
494\r
495 if (EFI_ERROR (Status)) {\r
496 return Status;\r
497 }\r
498\r
499 Private->RxToken.Status = EFI_NOT_READY;\r
500\r
501 return Private->Ip6->Receive (Private->Ip6, &Private->RxToken);\r
502}\r
503\r
504/**\r
505 Remove the timeout request from the list.\r
506\r
507 @param[in] Event A EFI_EVENT type event.\r
508 @param[in] Context The pointer to Context.\r
509\r
510**/\r
511VOID\r
512EFIAPI\r
513Ping6OnTimerRoutine (\r
514 IN EFI_EVENT Event,\r
515 IN VOID *Context\r
516 )\r
517{\r
518 EFI_STATUS Status;\r
519 PING6_PRIVATE_DATA *Private;\r
520 PING6_ICMP6_TX_INFO *TxInfo;\r
521 LIST_ENTRY *Entry;\r
522 LIST_ENTRY *NextEntry;\r
cda10fe4 523 UINT64 Time;\r
a3bcde70
HT
524\r
525 Private = (PING6_PRIVATE_DATA *) Context;\r
526\r
527 //\r
528 // Retransmit icmp6 echo request packets per second in sendnumber times.\r
529 //\r
530 if (Private->TxCount < Private->SendNum) {\r
531\r
532 Status = Ping6SendEchoRequest (Private);\r
533 if (Private->TxCount != 0){\r
534 if (EFI_ERROR (Status)) {\r
535 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SEND_REQUEST), mHiiHandle, Private->TxCount + 1);\r
536 }\r
537 }\r
538 }\r
539 //\r
540 // Check whether any icmp6 echo request in the list timeout.\r
541 //\r
542 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
543 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
544 Time = Ping6CalculateTick (TxInfo->TimeStamp, ReadTime ());\r
545\r
546 //\r
547 // Remove the timeout echo request from txlist.\r
548 //\r
549 if (Time > PING6_DEFAULT_TIMEOUT) {\r
550\r
551 if (EFI_ERROR (TxInfo->Token->Status)) {\r
552 Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
553 }\r
554 //\r
555 // Remove the timeout icmp6 echo request from list.\r
556 //\r
557 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_TIMEOUT), mHiiHandle, TxInfo->SequenceNum);\r
558\r
559 RemoveEntryList (&TxInfo->Link);\r
560 Ping6DestroyTxInfo (TxInfo);\r
561\r
562 if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
563 //\r
564 // All the left icmp6 echo request in the list timeout.\r
565 //\r
566 Private->Status = EFI_TIMEOUT;\r
567 }\r
568 }\r
569 }\r
570}\r
571\r
572/**\r
573 Create a valid IP6 instance.\r
574\r
575 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
576\r
577 @retval EFI_SUCCESS Create a valid IP6 instance successfully.\r
578 @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully.\r
579 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address.\r
580 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
581 @retval EFI_NOT_FOUND The source address is not found.\r
582**/\r
583EFI_STATUS\r
584Ping6CreateIp6Instance (\r
585 IN PING6_PRIVATE_DATA *Private\r
586 )\r
587{\r
588 EFI_STATUS Status;\r
589 UINTN HandleIndex;\r
590 UINTN HandleNum;\r
591 EFI_HANDLE *HandleBuffer;\r
592 EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb;\r
593 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
594 EFI_IP6_CONFIG_DATA Ip6Config;\r
595 EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;\r
596 UINTN IfInfoSize;\r
597 EFI_IPv6_ADDRESS *Addr;\r
598 UINTN AddrIndex;\r
599\r
600 HandleBuffer = NULL;\r
601 Ip6Sb = NULL;\r
602 IfInfo = NULL;\r
603 IfInfoSize = 0;\r
604\r
605 //\r
606 // Locate all the handles with ip6 service binding protocol.\r
607 //\r
608 Status = gBS->LocateHandleBuffer (\r
609 ByProtocol,\r
610 &gEfiIp6ServiceBindingProtocolGuid,\r
611 NULL,\r
612 &HandleNum,\r
613 &HandleBuffer\r
614 );\r
615 if (EFI_ERROR (Status) || (HandleNum == 0)) {\r
616 return EFI_ABORTED;\r
617 }\r
618 //\r
619 // Source address is required when pinging a link-local address on multi-\r
620 // interfaces host.\r
621 //\r
622 if (NetIp6IsLinkLocalAddr (&Private->DstAddress) &&\r
623 NetIp6IsUnspecifiedAddr (&Private->SrcAddress) &&\r
624 (HandleNum > 1)) {\r
625 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), mHiiHandle);\r
626 Status = EFI_INVALID_PARAMETER;\r
627 goto ON_ERROR;\r
628 }\r
629 //\r
630 // For each ip6 protocol, check interface addresses list.\r
631 //\r
632 for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
633\r
634 Ip6Sb = NULL;\r
635 IfInfo = NULL;\r
636 IfInfoSize = 0;\r
637\r
638 Status = gBS->HandleProtocol (\r
639 HandleBuffer[HandleIndex],\r
640 &gEfiIp6ServiceBindingProtocolGuid,\r
641 (VOID **) &Ip6Sb\r
642 );\r
643 if (EFI_ERROR (Status)) {\r
644 goto ON_ERROR;\r
645 }\r
646\r
647 if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) {\r
648 //\r
649 // No need to match interface address.\r
650 //\r
651 break;\r
652 } else {\r
653 //\r
654 // Ip6config protocol and ip6 service binding protocol are installed\r
655 // on the same handle.\r
656 //\r
657 Status = gBS->HandleProtocol (\r
658 HandleBuffer[HandleIndex],\r
659 &gEfiIp6ConfigProtocolGuid,\r
660 (VOID **) &Ip6Cfg\r
661 );\r
662\r
663 if (EFI_ERROR (Status)) {\r
664 goto ON_ERROR;\r
665 }\r
666 //\r
667 // Get the interface information size.\r
668 //\r
669 Status = Ip6Cfg->GetData (\r
670 Ip6Cfg,\r
671 Ip6ConfigDataTypeInterfaceInfo,\r
672 &IfInfoSize,\r
673 NULL\r
674 );\r
675\r
676 if (Status != EFI_BUFFER_TOO_SMALL) {\r
677 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), mHiiHandle, Status);\r
678 goto ON_ERROR;\r
679 }\r
680\r
681 IfInfo = AllocateZeroPool (IfInfoSize);\r
682\r
683 if (IfInfo == NULL) {\r
684 Status = EFI_OUT_OF_RESOURCES;\r
685 goto ON_ERROR;\r
686 }\r
687 //\r
688 // Get the interface info.\r
689 //\r
690 Status = Ip6Cfg->GetData (\r
691 Ip6Cfg,\r
692 Ip6ConfigDataTypeInterfaceInfo,\r
693 &IfInfoSize,\r
694 IfInfo\r
695 );\r
696\r
697 if (EFI_ERROR (Status)) {\r
698 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), mHiiHandle, Status);\r
699 goto ON_ERROR;\r
700 }\r
701 //\r
702 // Check whether the source address is one of the interface addresses.\r
703 //\r
704 for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) {\r
705\r
706 Addr = &(IfInfo->AddressInfo[AddrIndex].Address);\r
707 if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
708 //\r
709 // Match a certain interface address.\r
710 //\r
711 break;\r
712 }\r
713 }\r
714\r
715 if (AddrIndex < IfInfo->AddressInfoCount) {\r
716 //\r
717 // Found a nic handle with right interface address.\r
718 //\r
719 break;\r
720 }\r
721 }\r
722\r
723 FreePool (IfInfo);\r
724 IfInfo = NULL;\r
725 }\r
726 //\r
727 // No exact interface address matched.\r
728 //\r
729\r
730 if (HandleIndex == HandleNum) {\r
731 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND), mHiiHandle, mIp6SrcString);\r
732 Status = EFI_NOT_FOUND;\r
733 goto ON_ERROR;\r
734 }\r
735\r
736 Private->NicHandle = HandleBuffer[HandleIndex];\r
737\r
738 ASSERT (Ip6Sb != NULL);\r
739 Status = Ip6Sb->CreateChild (Ip6Sb, &Private->Ip6ChildHandle);\r
740\r
741 if (EFI_ERROR (Status)) {\r
742 goto ON_ERROR;\r
743 }\r
744\r
745 Status = gBS->OpenProtocol (\r
746 Private->Ip6ChildHandle,\r
747 &gEfiIp6ProtocolGuid,\r
748 (VOID **) &Private->Ip6,\r
749 Private->ImageHandle,\r
750 Private->Ip6ChildHandle,\r
751 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
752 );\r
753 if (EFI_ERROR (Status)) {\r
754 goto ON_ERROR;\r
755 }\r
756\r
757 ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
758\r
759 //\r
760 // Configure the ip6 instance for icmp6 packet exchange.\r
761 //\r
762 Ip6Config.DefaultProtocol = 58;\r
763 Ip6Config.AcceptAnyProtocol = FALSE;\r
764 Ip6Config.AcceptIcmpErrors = TRUE;\r
765 Ip6Config.AcceptPromiscuous = FALSE;\r
766 Ip6Config.TrafficClass = 0;\r
767 Ip6Config.HopLimit = 128;\r
768 Ip6Config.FlowLabel = 0;\r
769 Ip6Config.ReceiveTimeout = 0;\r
770 Ip6Config.TransmitTimeout = 0;\r
771\r
772 IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
773\r
774 IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
775\r
776 Status = Private->Ip6->Configure (Private->Ip6, &Ip6Config);\r
777\r
778 if (EFI_ERROR (Status)) {\r
779 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_CONFIG), mHiiHandle, Status);\r
780 goto ON_ERROR;\r
781 }\r
782\r
783 return EFI_SUCCESS;\r
784\r
785ON_ERROR:\r
786 if (HandleBuffer != NULL) {\r
787 FreePool (HandleBuffer);\r
788 }\r
789\r
790 if (IfInfo != NULL) {\r
791 FreePool (IfInfo);\r
792 }\r
793\r
794 if ((Ip6Sb != NULL) && (Private->Ip6ChildHandle != NULL)) {\r
795 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
796 }\r
797\r
798 return Status;\r
799}\r
800\r
801/**\r
75dce340 802 Destroy the IP6 instance.\r
a3bcde70
HT
803\r
804 @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
805\r
806**/\r
807VOID\r
75dce340 808Ping6DestroyIp6Instance (\r
a3bcde70
HT
809 IN PING6_PRIVATE_DATA *Private\r
810 )\r
811{\r
812 EFI_STATUS Status;\r
813 EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb;\r
814\r
815 gBS->CloseProtocol (\r
816 Private->Ip6ChildHandle,\r
817 &gEfiIp6ProtocolGuid,\r
818 Private->ImageHandle,\r
819 Private->Ip6ChildHandle\r
820 );\r
821\r
822 Status = gBS->HandleProtocol (\r
823 Private->NicHandle,\r
824 &gEfiIp6ServiceBindingProtocolGuid,\r
825 (VOID **) &Ip6Sb\r
826 );\r
827\r
828 if (!EFI_ERROR(Status)) {\r
829 Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
830 }\r
831}\r
832\r
833/**\r
834 The Ping6 Process.\r
835\r
836 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
837 @param[in] SendNumber The send request count.\r
838 @param[in] BufferSize The send buffer size.\r
839 @param[in] SrcAddress The source IPv6 address.\r
840 @param[in] DstAddress The destination IPv6 address.\r
841\r
842 @retval EFI_SUCCESS The ping6 processed successfullly.\r
843 @retval others The ping6 processed unsuccessfully.\r
844\r
845**/\r
846EFI_STATUS\r
847Ping6 (\r
848 IN EFI_HANDLE ImageHandle,\r
849 IN UINT32 SendNumber,\r
850 IN UINT32 BufferSize,\r
851 IN EFI_IPv6_ADDRESS *SrcAddress,\r
852 IN EFI_IPv6_ADDRESS *DstAddress\r
853 )\r
854{\r
855 EFI_STATUS Status;\r
856 EFI_INPUT_KEY Key;\r
857 PING6_PRIVATE_DATA *Private;\r
858 PING6_ICMP6_TX_INFO *TxInfo;\r
859 LIST_ENTRY *Entry;\r
860 LIST_ENTRY *NextEntry;\r
861\r
862 Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA));\r
863\r
864 ASSERT (Private != NULL);\r
865\r
866 Private->ImageHandle = ImageHandle;\r
867 Private->SendNum = SendNumber;\r
868 Private->BufferSize = BufferSize;\r
cda10fe4 869 Private->RttMin = ~((UINT64 )(0x0));\r
a3bcde70
HT
870 Private->Status = EFI_NOT_READY;\r
871\r
872 InitializeListHead (&Private->TxList);\r
873\r
874 IP6_COPY_ADDRESS (&Private->SrcAddress, SrcAddress);\r
875 IP6_COPY_ADDRESS (&Private->DstAddress, DstAddress);\r
876\r
877 //\r
878 // Open and configure a ip6 instance for ping6.\r
879 //\r
880 Status = Ping6CreateIp6Instance (Private);\r
881\r
882 if (EFI_ERROR (Status)) {\r
883 goto ON_EXIT;\r
884 }\r
885 //\r
886 // Print the command line itself.\r
887 //\r
888 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_START), mHiiHandle, mIp6DstString, Private->BufferSize);\r
889 //\r
890 // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
891 //\r
892 Status = Ping6ReceiveEchoReply (Private);\r
893\r
894 if (EFI_ERROR (Status)) {\r
895 goto ON_EXIT;\r
896 }\r
897 //\r
898 // Create and start timer to send icmp6 echo request packet per second.\r
899 //\r
900 Status = gBS->CreateEvent (\r
901 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
902 TPL_CALLBACK,\r
903 Ping6OnTimerRoutine,\r
904 Private,\r
905 &Private->Timer\r
906 );\r
907\r
908 if (EFI_ERROR (Status)) {\r
909 goto ON_EXIT;\r
910 }\r
911 //\r
912 // Create a ipv6 token to send the first icmp6 echo request packet.\r
913 //\r
914 Status = Ping6SendEchoRequest (Private);\r
915 //\r
916 // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
917 //\r
918 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
919 if(Status == EFI_NOT_FOUND) {\r
920 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN), mHiiHandle, mIp6DstString);\r
921 }\r
922\r
923 goto ON_EXIT;\r
924 }\r
925\r
926 Status = gBS->SetTimer (\r
927 Private->Timer,\r
928 TimerPeriodic,\r
929 PING6_ONE_SECOND\r
930 );\r
931\r
932 if (EFI_ERROR (Status)) {\r
933 goto ON_EXIT;\r
934 }\r
935 //\r
936 // Control the ping6 process by two factors:\r
937 // 1. Hot key\r
938 // 2. Private->Status\r
939 // 2.1. success means all icmp6 echo request packets get reply packets.\r
940 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
941 // 2.3. noready means ping6 process is on-the-go.\r
942 //\r
943 while (Private->Status == EFI_NOT_READY) {\r
944 Private->Ip6->Poll (Private->Ip6);\r
945\r
946 //\r
947 // Terminate the ping6 process by 'esc' or 'ctl-c'.\r
948 //\r
949 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
950\r
951 if (!EFI_ERROR(Status)) {\r
952 if ((Key.UnicodeChar == 0x1b) || (Key.UnicodeChar == 0x03) ||\r
953 ((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_ESC))) {\r
954 goto ON_STAT;\r
955 }\r
956 }\r
957 }\r
958\r
959ON_STAT:\r
960 //\r
961 // Display the statistics in all.\r
962 //\r
963 gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
964\r
965 if (Private->TxCount != 0) {\r
966 ShellPrintHiiEx (\r
967 -1,\r
968 -1,\r
969 NULL,\r
970 STRING_TOKEN (STR_PING6_STAT),\r
971 mHiiHandle,\r
972 Private->TxCount,\r
973 Private->RxCount,\r
974 (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,\r
975 Private->RttSum\r
976 );\r
977 }\r
978\r
979 if (Private->RxCount != 0) {\r
980 ShellPrintHiiEx (\r
981 -1,\r
982 -1,\r
983 NULL,\r
984 STRING_TOKEN (STR_PING6_RTT),\r
985 mHiiHandle,\r
986 Private->RttMin,\r
987 Private->RttMax,\r
cda10fe4 988 DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL)\r
a3bcde70
HT
989 );\r
990 }\r
991\r
992ON_EXIT:\r
993\r
994 if (Private != NULL) {\r
995 Private->Status = EFI_ABORTED;\r
996\r
997 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
998 TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
999\r
1000 Status = Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
1001\r
1002 RemoveEntryList (&TxInfo->Link);\r
1003 Ping6DestroyTxInfo (TxInfo);\r
1004 }\r
1005\r
1006 if (Private->Timer != NULL) {\r
1007 gBS->CloseEvent (Private->Timer);\r
1008 }\r
1009\r
1010 if (Private->Ip6 != NULL) {\r
1011 Status = Private->Ip6->Cancel (Private->Ip6, &Private->RxToken);\r
1012 }\r
1013\r
1014 if (Private->RxToken.Event != NULL) {\r
1015 gBS->CloseEvent (Private->RxToken.Event);\r
1016 }\r
1017\r
1018 if (Private->Ip6ChildHandle != NULL) {\r
75dce340 1019 Ping6DestroyIp6Instance (Private);\r
a3bcde70
HT
1020 }\r
1021\r
1022 FreePool (Private);\r
1023 }\r
1024\r
1025 return Status;\r
1026}\r
1027\r
1028/**\r
1029 This is the declaration of an EFI image entry point. This entry point is\r
1030 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including\r
1031 both device drivers and bus drivers.\r
1032\r
1033 The entry point for the Ping6 application that parses the command line input and calls the Ping6 process.\r
1034\r
1035 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
1036 @param[in] SystemTable A pointer to the EFI System Table.\r
1037\r
1038 @retval EFI_SUCCESS The operation completed successfully.\r
1039 @retval EFI_INVALID_PARAMETETR Input parameters combination is invalid.\r
1040 @retval Others Some errors occur.\r
1041\r
1042**/\r
1043EFI_STATUS\r
1044EFIAPI\r
1045InitializePing6 (\r
1046 IN EFI_HANDLE ImageHandle,\r
1047 IN EFI_SYSTEM_TABLE *SystemTable\r
1048 )\r
1049{\r
1050 EFI_STATUS Status;\r
1051 EFI_IPv6_ADDRESS DstAddress;\r
1052 EFI_IPv6_ADDRESS SrcAddress;\r
1053 UINT64 BufferSize;\r
1054 UINTN SendNumber;\r
1055 LIST_ENTRY *ParamPackage;\r
1056 CONST CHAR16 *ValueStr;\r
1057 CONST CHAR16 *ValueStrPtr;\r
1058 UINTN NonOptionCount;\r
be6cd654 1059 EFI_HII_PACKAGE_LIST_HEADER *PackageList;\r
a3bcde70
HT
1060\r
1061 //\r
be6cd654 1062 // Retrieve HII package list from ImageHandle\r
a3bcde70 1063 //\r
be6cd654
ZL
1064 Status = gBS->OpenProtocol (\r
1065 ImageHandle,\r
1066 &gEfiHiiPackageListProtocolGuid,\r
1067 (VOID **) &PackageList,\r
1068 ImageHandle,\r
1069 NULL,\r
1070 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1071 );\r
1072 if (EFI_ERROR (Status)) {\r
1073 return Status;\r
1074 }\r
1075\r
1076 //\r
1077 // Publish HII package list to HII Database.\r
1078 //\r
1079 Status = gHiiDatabase->NewPackageList (\r
1080 gHiiDatabase,\r
1081 PackageList,\r
1082 NULL,\r
1083 &mHiiHandle\r
1084 );\r
1085 if (EFI_ERROR (Status)) {\r
1086 return Status;\r
1087 }\r
1088 \r
a3bcde70
HT
1089 ASSERT (mHiiHandle != NULL);\r
1090\r
1091 Status = ShellCommandLineParseEx (Ping6ParamList, &ParamPackage, NULL, TRUE, FALSE);\r
1092 if (EFI_ERROR(Status)) {\r
1093 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), mHiiHandle);\r
1094 goto ON_EXIT;\r
1095 }\r
1096\r
a3bcde70
HT
1097 SendNumber = 10;\r
1098 BufferSize = 16;\r
1099\r
1100 //\r
1101 // Parse the paramter of count number.\r
1102 //\r
1103 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
1104 ValueStrPtr = ValueStr;\r
1105 if (ValueStr != NULL) {\r
1106 SendNumber = ShellStrToUintn (ValueStrPtr);\r
1107\r
1108 //\r
1109 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1110 //\r
1111 if ((SendNumber == 0) || (SendNumber > PING6_MAX_SEND_NUMBER)) {\r
1112 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER), mHiiHandle, ValueStr);\r
1113 Status = EFI_INVALID_PARAMETER;\r
1114 goto ON_EXIT;\r
1115 }\r
1116 }\r
1117 //\r
1118 // Parse the paramter of buffer size.\r
1119 //\r
1120 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
1121 ValueStrPtr = ValueStr;\r
1122 if (ValueStr != NULL) {\r
1123 BufferSize = ShellStrToUintn (ValueStrPtr);\r
1124\r
1125 //\r
1126 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
1127 //\r
1128 if ((BufferSize < 16) || (BufferSize > PING6_MAX_BUFFER_SIZE)) {\r
1129 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE), mHiiHandle, ValueStr);\r
1130 Status = EFI_INVALID_PARAMETER;\r
1131 goto ON_EXIT;\r
1132 }\r
1133 }\r
1134\r
1135 ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
1136 ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
1137\r
1138 //\r
1139 // Parse the paramter of source ip address.\r
1140 //\r
1141 ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
1142 ValueStrPtr = ValueStr;\r
1143 if (ValueStr != NULL) {\r
1144 mIp6SrcString = ValueStr;\r
1145 Status = NetLibStrToIp6 (ValueStrPtr, &SrcAddress);\r
1146 if (EFI_ERROR (Status)) {\r
1147 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), mHiiHandle, ValueStr);\r
1148 Status = EFI_INVALID_PARAMETER;\r
1149 goto ON_EXIT;\r
1150 }\r
1151 }\r
1152 //\r
1153 // Parse the paramter of destination ip address.\r
1154 //\r
780847d1 1155 NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
a3bcde70
HT
1156 ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1));\r
1157 if (NonOptionCount != 2) {\r
1158 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), mHiiHandle);\r
1159 Status = EFI_INVALID_PARAMETER;\r
1160 goto ON_EXIT;\r
1161 }\r
1162 ValueStrPtr = ValueStr;\r
1163 if (ValueStr != NULL) {\r
1164 mIp6DstString = ValueStr;\r
1165 Status = NetLibStrToIp6 (ValueStrPtr, &DstAddress);\r
1166 if (EFI_ERROR (Status)) {\r
1167 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), mHiiHandle, ValueStr);\r
1168 Status = EFI_INVALID_PARAMETER;\r
1169 goto ON_EXIT;\r
1170 }\r
1171 }\r
1172 //\r
1173 // Get frequency to calculate the time from ticks.\r
1174 //\r
1175 Status = Ping6GetFrequency ();\r
1176\r
1177 if (EFI_ERROR(Status)) {\r
1178 goto ON_EXIT;\r
1179 }\r
1180 //\r
1181 // Enter into ping6 process.\r
1182 //\r
1183 Status = Ping6 (\r
1184 ImageHandle,\r
1185 (UINT32)SendNumber,\r
1186 (UINT32)BufferSize,\r
1187 &SrcAddress,\r
1188 &DstAddress\r
1189 );\r
1190\r
1191ON_EXIT:\r
1192 ShellCommandLineFreeVarList (ParamPackage);\r
1193 HiiRemovePackages (mHiiHandle);\r
1194 return Status;\r
1195}\r