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