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