ShellPkg: update ping6 to use timer service instead of timer arch protocol .
This patch update the shell ping command to use timer service to calculate the RTT time, instead of using the timer arch protocol. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo <lubo.zhang@intel.com> Cc: Ni Ruiyu <ruiyu.ni@intel.com> Cc: Ye Ting <ting.ye@intel.com> Cc: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
This commit is contained in:
@ -19,12 +19,7 @@
|
|||||||
#define PING6_MAX_SEND_NUMBER 10000
|
#define PING6_MAX_SEND_NUMBER 10000
|
||||||
#define PING6_MAX_BUFFER_SIZE 32768
|
#define PING6_MAX_BUFFER_SIZE 32768
|
||||||
#define PING6_ONE_SECOND 10000000
|
#define PING6_ONE_SECOND 10000000
|
||||||
|
#define STALL_1_MILLI_SECOND 1000
|
||||||
//
|
|
||||||
// A similar amount of time that passes in femtoseconds
|
|
||||||
// for each increment of TimerValue. It is for NT32 only.
|
|
||||||
//
|
|
||||||
#define NTTIMERPERIOD 358049
|
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
@ -34,7 +29,7 @@ typedef struct _ICMP6_ECHO_REQUEST_REPLY {
|
|||||||
UINT16 Checksum;
|
UINT16 Checksum;
|
||||||
UINT16 Identifier;
|
UINT16 Identifier;
|
||||||
UINT16 SequenceNum;
|
UINT16 SequenceNum;
|
||||||
UINT64 TimeStamp;
|
UINT32 TimeStamp;
|
||||||
UINT8 Data[1];
|
UINT8 Data[1];
|
||||||
} ICMP6_ECHO_REQUEST_REPLY;
|
} ICMP6_ECHO_REQUEST_REPLY;
|
||||||
|
|
||||||
@ -43,7 +38,7 @@ typedef struct _ICMP6_ECHO_REQUEST_REPLY {
|
|||||||
typedef struct _PING6_ICMP6_TX_INFO {
|
typedef struct _PING6_ICMP6_TX_INFO {
|
||||||
LIST_ENTRY Link;
|
LIST_ENTRY Link;
|
||||||
UINT16 SequenceNum;
|
UINT16 SequenceNum;
|
||||||
UINT64 TimeStamp;
|
UINT32 TimeStamp;
|
||||||
EFI_IP6_COMPLETION_TOKEN *Token;
|
EFI_IP6_COMPLETION_TOKEN *Token;
|
||||||
} PING6_ICMP6_TX_INFO;
|
} PING6_ICMP6_TX_INFO;
|
||||||
|
|
||||||
@ -54,6 +49,10 @@ typedef struct _PING6_PRIVATE_DATA {
|
|||||||
EFI_IP6_PROTOCOL *Ip6;
|
EFI_IP6_PROTOCOL *Ip6;
|
||||||
EFI_EVENT Timer;
|
EFI_EVENT Timer;
|
||||||
|
|
||||||
|
UINT32 TimerPeriod;
|
||||||
|
UINT32 RttTimerTick;
|
||||||
|
EFI_EVENT RttTimer;
|
||||||
|
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
LIST_ENTRY TxList;
|
LIST_ENTRY TxList;
|
||||||
EFI_IP6_COMPLETION_TOKEN RxToken;
|
EFI_IP6_COMPLETION_TOKEN RxToken;
|
||||||
@ -99,96 +98,189 @@ SHELL_PARAM_ITEM Ping6ParamList[] = {
|
|||||||
//
|
//
|
||||||
CONST CHAR16 *mIp6DstString;
|
CONST CHAR16 *mIp6DstString;
|
||||||
CONST CHAR16 *mIp6SrcString;
|
CONST CHAR16 *mIp6SrcString;
|
||||||
UINT64 mFrequency = 0;
|
|
||||||
UINT64 mIp6CurrentTick = 0;
|
|
||||||
EFI_CPU_ARCH_PROTOCOL *Cpu = NULL;
|
EFI_CPU_ARCH_PROTOCOL *Cpu = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads and returns the current value of the Time.
|
RTT timer tick routine.
|
||||||
|
|
||||||
@return The current tick value.
|
@param[in] Event A EFI_EVENT type event.
|
||||||
|
@param[in] Context The pointer to Context.
|
||||||
|
|
||||||
**/
|
**/
|
||||||
UINT64
|
VOID
|
||||||
Ping6ReadTime ()
|
EFIAPI
|
||||||
|
Ping6RttTimerTickRoutine (
|
||||||
|
IN EFI_EVENT Event,
|
||||||
|
IN VOID *Context
|
||||||
|
)
|
||||||
{
|
{
|
||||||
UINT64 TimerPeriod;
|
UINT32 *RttTimerTick;
|
||||||
EFI_STATUS Status;
|
|
||||||
|
|
||||||
ASSERT (Cpu != NULL);
|
RttTimerTick = (UINT32*) Context;
|
||||||
|
(*RttTimerTick)++;
|
||||||
Status = Cpu->GetTimerValue (Cpu, 0, &mIp6CurrentTick, &TimerPeriod);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
//
|
|
||||||
// The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
|
|
||||||
// TimerPeriod by ourselves.
|
|
||||||
//
|
|
||||||
mIp6CurrentTick += 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mIp6CurrentTick;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get and calculate the frequency in tick/ms.
|
Get the timer period of the system.
|
||||||
The result is saved in the globle variable mFrequency
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Calculated the frequency successfully.
|
This function tries to get the system timer period by creating
|
||||||
@retval Others Failed to calculate the frequency.
|
an 1ms period timer.
|
||||||
|
|
||||||
|
@return System timer period in MS, or 0 if operation failed.
|
||||||
|
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
UINT32
|
||||||
Ping6GetFrequency (
|
Ping6GetTimerPeriod(
|
||||||
VOID
|
VOID
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
UINT64 CurrentTick;
|
UINT32 RttTimerTick;
|
||||||
UINT64 TimerPeriod;
|
EFI_EVENT TimerEvent;
|
||||||
|
UINT32 StallCounter;
|
||||||
|
EFI_TPL OldTpl;
|
||||||
|
|
||||||
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);
|
RttTimerTick = 0;
|
||||||
|
StallCounter = 0;
|
||||||
|
|
||||||
|
Status = gBS->CreateEvent (
|
||||||
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
||||||
|
TPL_NOTIFY,
|
||||||
|
Ping6RttTimerTickRoutine,
|
||||||
|
&RttTimerTick,
|
||||||
|
&TimerEvent
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||||
|
Status = gBS->SetTimer (
|
||||||
|
TimerEvent,
|
||||||
|
TimerPeriodic,
|
||||||
|
TICKS_PER_MS
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
gBS->CloseEvent (TimerEvent);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (RttTimerTick < 10) {
|
||||||
|
gBS->Stall (STALL_1_MILLI_SECOND);
|
||||||
|
++StallCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
gBS->RestoreTPL (OldTpl);
|
||||||
|
|
||||||
|
gBS->SetTimer (TimerEvent, TimerCancel, 0);
|
||||||
|
gBS->CloseEvent (TimerEvent);
|
||||||
|
|
||||||
|
return StallCounter / RttTimerTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize the timer event for RTT (round trip time).
|
||||||
|
|
||||||
|
@param[in] Private The pointer to PING6_PRIVATE_DATA.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS RTT timer is started.
|
||||||
|
@retval Others Failed to start the RTT timer.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
Ping6InitRttTimer (
|
||||||
|
IN PING6_PRIVATE_DATA *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
Private->TimerPeriod = Ping6GetTimerPeriod ();
|
||||||
|
if (Private->TimerPeriod == 0) {
|
||||||
|
return EFI_ABORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Private->RttTimerTick = 0;
|
||||||
|
Status = gBS->CreateEvent (
|
||||||
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
||||||
|
TPL_NOTIFY,
|
||||||
|
Ping6RttTimerTickRoutine,
|
||||||
|
&Private->RttTimerTick,
|
||||||
|
&Private->RttTimer
|
||||||
|
);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod);
|
Status = gBS->SetTimer (
|
||||||
|
Private->RttTimer,
|
||||||
|
TimerPeriodic,
|
||||||
|
TICKS_PER_MS
|
||||||
|
);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
//
|
gBS->CloseEvent (Private->RttTimer);
|
||||||
// For NT32 Simulator only. 358049 is a similar value to keep timer granularity.
|
return Status;
|
||||||
// Set the timer period by ourselves.
|
|
||||||
//
|
|
||||||
TimerPeriod = (UINT64) NTTIMERPERIOD;
|
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// The timer period is in femtosecond (1 femtosecond is 1e-15 second).
|
|
||||||
// So 1e+12 is divided by timer period to produce the freq in tick/ms.
|
|
||||||
//
|
|
||||||
mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Free RTT timer event resource.
|
||||||
|
|
||||||
|
@param[in] Private The pointer to PING6_PRIVATE_DATA.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
Ping6FreeRttTimer (
|
||||||
|
IN PING6_PRIVATE_DATA *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Private->RttTimer != NULL) {
|
||||||
|
gBS->SetTimer (Private->RttTimer, TimerCancel, 0);
|
||||||
|
gBS->CloseEvent (Private->RttTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Read the current time.
|
||||||
|
|
||||||
|
@param[in] Private The pointer to PING6_PRIVATE_DATA.
|
||||||
|
|
||||||
|
@retval the current tick value.
|
||||||
|
**/
|
||||||
|
UINT32
|
||||||
|
Ping6ReadTime (
|
||||||
|
IN PING6_PRIVATE_DATA *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return Private->RttTimerTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get and calculate the duration in ms.
|
Get and calculate the duration in ms.
|
||||||
|
|
||||||
|
@param[in] Private The pointer to PING6_PRIVATE_DATA.
|
||||||
@param[in] Begin The start point of time.
|
@param[in] Begin The start point of time.
|
||||||
@param[in] End The end point of time.
|
@param[in] End The end point of time.
|
||||||
|
|
||||||
@return The duration in ms.
|
@return The duration in ms.
|
||||||
|
|
||||||
**/
|
**/
|
||||||
UINT64
|
UINT32
|
||||||
Ping6CalculateTick (
|
Ping6CalculateTick (
|
||||||
IN UINT64 Begin,
|
IN PING6_PRIVATE_DATA *Private,
|
||||||
IN UINT64 End
|
IN UINT32 Begin,
|
||||||
|
IN UINT32 End
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ASSERT (End > Begin);
|
if (End < Begin) {
|
||||||
return DivU64x64Remainder (End - Begin, mFrequency, NULL);
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (End - Begin) * Private->TimerPeriod;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -312,8 +404,7 @@ Ping6OnEchoReplyReceived6 (
|
|||||||
EFI_IP6_RECEIVE_DATA *RxData;
|
EFI_IP6_RECEIVE_DATA *RxData;
|
||||||
ICMP6_ECHO_REQUEST_REPLY *Reply;
|
ICMP6_ECHO_REQUEST_REPLY *Reply;
|
||||||
UINT32 PayLoad;
|
UINT32 PayLoad;
|
||||||
UINT64 Rtt;
|
UINT32 Rtt;
|
||||||
CHAR8 Near;
|
|
||||||
|
|
||||||
Private = (PING6_PRIVATE_DATA *) Context;
|
Private = (PING6_PRIVATE_DATA *) Context;
|
||||||
|
|
||||||
@ -352,12 +443,7 @@ Ping6OnEchoReplyReceived6 (
|
|||||||
//
|
//
|
||||||
// Display statistics on this icmp6 echo reply packet.
|
// Display statistics on this icmp6 echo reply packet.
|
||||||
//
|
//
|
||||||
Rtt = Ping6CalculateTick (Reply->TimeStamp, Ping6ReadTime ());
|
Rtt = Ping6CalculateTick (Private, Reply->TimeStamp, Ping6ReadTime (Private));
|
||||||
if (Rtt != 0) {
|
|
||||||
Near = (CHAR8) '=';
|
|
||||||
} else {
|
|
||||||
Near = (CHAR8) '<';
|
|
||||||
}
|
|
||||||
|
|
||||||
Private->RttSum += Rtt;
|
Private->RttSum += Rtt;
|
||||||
Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;
|
Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;
|
||||||
@ -373,8 +459,8 @@ Ping6OnEchoReplyReceived6 (
|
|||||||
mIp6DstString,
|
mIp6DstString,
|
||||||
Reply->SequenceNum,
|
Reply->SequenceNum,
|
||||||
RxData->Header->HopLimit,
|
RxData->Header->HopLimit,
|
||||||
Near,
|
Rtt,
|
||||||
Rtt
|
Rtt + Private->TimerPeriod
|
||||||
);
|
);
|
||||||
|
|
||||||
ON_EXIT:
|
ON_EXIT:
|
||||||
@ -415,7 +501,7 @@ ON_EXIT:
|
|||||||
EFI_IP6_COMPLETION_TOKEN *
|
EFI_IP6_COMPLETION_TOKEN *
|
||||||
Ping6GenerateToken (
|
Ping6GenerateToken (
|
||||||
IN PING6_PRIVATE_DATA *Private,
|
IN PING6_PRIVATE_DATA *Private,
|
||||||
IN UINT64 TimeStamp,
|
IN UINT32 TimeStamp,
|
||||||
IN UINT16 SequenceNum
|
IN UINT16 SequenceNum
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -513,7 +599,7 @@ Ping6SendEchoRequest (
|
|||||||
return EFI_OUT_OF_RESOURCES;
|
return EFI_OUT_OF_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
TxInfo->TimeStamp = Ping6ReadTime ();
|
TxInfo->TimeStamp = Ping6ReadTime (Private);
|
||||||
TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);
|
TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);
|
||||||
|
|
||||||
TxInfo->Token = Ping6GenerateToken (
|
TxInfo->Token = Ping6GenerateToken (
|
||||||
@ -615,7 +701,7 @@ Ping6OnTimerRoutine6 (
|
|||||||
//
|
//
|
||||||
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {
|
||||||
TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);
|
TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);
|
||||||
Time = Ping6CalculateTick (TxInfo->TimeStamp, Ping6ReadTime ());
|
Time = Ping6CalculateTick (Private, TxInfo->TimeStamp, Ping6ReadTime (Private));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Remove the timeout echo request from txlist.
|
// Remove the timeout echo request from txlist.
|
||||||
@ -1015,6 +1101,16 @@ ShellPing6 (
|
|||||||
ShellStatus = SHELL_ACCESS_DENIED;
|
ShellStatus = SHELL_ACCESS_DENIED;
|
||||||
goto ON_EXIT;
|
goto ON_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Start a timer to calculate the RTT.
|
||||||
|
//
|
||||||
|
Status = Ping6InitRttTimer (Private);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
ShellStatus = SHELL_ACCESS_DENIED;
|
||||||
|
goto ON_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create a ipv6 token to send the first icmp6 echo request packet.
|
// Create a ipv6 token to send the first icmp6 echo request packet.
|
||||||
//
|
//
|
||||||
@ -1093,8 +1189,11 @@ ON_STAT:
|
|||||||
STRING_TOKEN (STR_PING6_RTT),
|
STRING_TOKEN (STR_PING6_RTT),
|
||||||
gShellNetwork2HiiHandle,
|
gShellNetwork2HiiHandle,
|
||||||
Private->RttMin,
|
Private->RttMin,
|
||||||
|
Private->RttMin + Private->TimerPeriod,
|
||||||
Private->RttMax,
|
Private->RttMax,
|
||||||
DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL)
|
Private->RttMax + Private->TimerPeriod,
|
||||||
|
DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL),
|
||||||
|
DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + Private->TimerPeriod
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1112,6 +1211,8 @@ ON_EXIT:
|
|||||||
Ping6DestroyTxInfo (TxInfo);
|
Ping6DestroyTxInfo (TxInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ping6FreeRttTimer (Private);
|
||||||
|
|
||||||
if (Private->Timer != NULL) {
|
if (Private->Timer != NULL) {
|
||||||
gBS->CloseEvent (Private->Timer);
|
gBS->CloseEvent (Private->Timer);
|
||||||
}
|
}
|
||||||
@ -1248,15 +1349,7 @@ ShellCommandRunPing6 (
|
|||||||
goto ON_EXIT;
|
goto ON_EXIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// Get frequency to calculate the time from ticks.
|
|
||||||
//
|
|
||||||
Status = Ping6GetFrequency ();
|
|
||||||
|
|
||||||
if (EFI_ERROR(Status)) {
|
|
||||||
ShellStatus = SHELL_ACCESS_DENIED;
|
|
||||||
goto ON_EXIT;
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
// Enter into ping6 process.
|
// Enter into ping6 process.
|
||||||
//
|
//
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
|
|
||||||
[Protocols]
|
[Protocols]
|
||||||
gEfiCpuArchProtocolGuid ## CONSUMES
|
gEfiCpuArchProtocolGuid ## CONSUMES
|
||||||
|
gEfiTimerArchProtocolGuid
|
||||||
gEfiIp6ProtocolGuid ## SOMETIMES_CONSUMES
|
gEfiIp6ProtocolGuid ## SOMETIMES_CONSUMES
|
||||||
gEfiIp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
|
gEfiIp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
|
||||||
gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES
|
gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES
|
||||||
|
@ -38,9 +38,9 @@
|
|||||||
#string STR_PING6_NOSOURCE_INDOMAIN #language en-US "No sources in %s's multicast domain.\r\n"
|
#string STR_PING6_NOSOURCE_INDOMAIN #language en-US "No sources in %s's multicast domain.\r\n"
|
||||||
#string STR_PING6_START #language en-US "Ping %s %d data bytes\r\n"
|
#string STR_PING6_START #language en-US "Ping %s %d data bytes\r\n"
|
||||||
#string STR_PING6_TIMEOUT #language en-US "Echo request sequence %d timeout.\r\n"
|
#string STR_PING6_TIMEOUT #language en-US "Echo request sequence %d timeout.\r\n"
|
||||||
#string STR_PING6_REPLY_INFO #language en-US "%d bytes from %s : icmp_seq=%d ttl=%d time%c%dms\r\n"
|
#string STR_PING6_REPLY_INFO #language en-US "%d bytes from %s : icmp_seq=%d ttl=%d time%d~%dms\r\n"
|
||||||
#string STR_PING6_STAT #language en-US "\n%d packets transmitted, %d received, %d%% packet loss, time %dms\r\n"
|
#string STR_PING6_STAT #language en-US "\n%d packets transmitted, %d received, %d%% packet loss, time %dms\r\n"
|
||||||
#string STR_PING6_RTT #language en-US "\nRtt(round trip time) min=%dms max=%dms avg=%dms\r\n"
|
#string STR_PING6_RTT #language en-US "\nRtt(round trip time) min=%d~%dms max=%d~%dms avg=%d~%dms\r\n"
|
||||||
|
|
||||||
#string STR_IFCONFIG6_ERR_IP6CFG_GETDATA #language en-US "Get data of the interface information %hr\r\n"
|
#string STR_IFCONFIG6_ERR_IP6CFG_GETDATA #language en-US "Get data of the interface information %hr\r\n"
|
||||||
#string STR_IFCONFIG6_INFO_BREAK #language en-US "-----------------------------------------------------------------"
|
#string STR_IFCONFIG6_INFO_BREAK #language en-US "-----------------------------------------------------------------"
|
||||||
|
Reference in New Issue
Block a user