diff --git a/reactos/lib/rtl/network.c b/reactos/lib/rtl/network.c index e55d8141f24..0b163979409 100644 --- a/reactos/lib/rtl/network.c +++ b/reactos/lib/rtl/network.c @@ -19,6 +19,12 @@ /* maximum length of an ipv4 port expressed as a string */ #define IPV4_PORT_STRING_MAX_LEN 7 /* with the leading ':' */ +/* maximum length of an ipv6 string for RtlIpv6AddressToString */ +#define RTLIPV6A2S_MAX_LEN 46 + +/* maximum length of an ipv6 string with scope and port for RtlIpv6AddressToStringEx */ +#define RTLIPV6A2SEX_MAX_LEN 65 + /* network to host order conversion for little endian machines */ #define WN2H(w) (((w & 0xFF00) >> 8) | ((w & 0x00FF) << 8)) @@ -443,20 +449,38 @@ RtlIpv4StringToAddressExW( } /* -* @unimplemented +* @implemented */ PSTR NTAPI RtlIpv6AddressToStringA( _In_ const struct in6_addr *Addr, - _Out_writes_(46) PSTR S) + _Out_writes_(RTLIPV6A2S_MAX_LEN) PSTR S) { - UNIMPLEMENTED; - return NULL; + WCHAR Buffer[RTLIPV6A2S_MAX_LEN]; + PWSTR Result; + NTSTATUS Status; + + if (!S) + return (PSTR)~0; + + Buffer[0] = 0; + Result = RtlIpv6AddressToStringW(Addr, Buffer); + if (Result == (PWSTR)~0) + return (PSTR)~0; + + ASSERT(Result >= Buffer); + ASSERT(Result < Buffer + RTL_NUMBER_OF(Buffer)); + + Status = RtlUnicodeToMultiByteN(S, RTLIPV6A2S_MAX_LEN, NULL, Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + return (PSTR)~0; + + return S + strlen(S); } /* -* @unimplemented +* @implemented */ NTSTATUS NTAPI @@ -467,25 +491,135 @@ RtlIpv6AddressToStringExA( _Out_writes_to_(*AddressStringLength, *AddressStringLength) PSTR AddressString, _Inout_ PULONG AddressStringLength) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN]; + NTSTATUS Status; + + if (!Address || !AddressString || !AddressStringLength) + return STATUS_INVALID_PARAMETER; + + Status = RtlIpv6AddressToStringExW(Address, ScopeId, Port, Buffer, AddressStringLength); + if (!NT_SUCCESS(Status)) + return Status; + + Status = RtlUnicodeToMultiByteN(AddressString, RTLIPV6A2SEX_MAX_LEN, NULL, Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + return STATUS_INVALID_PARAMETER; + + return STATUS_SUCCESS; } /* -* @unimplemented +* @implemented */ PWSTR NTAPI RtlIpv6AddressToStringW( _In_ const struct in6_addr *Addr, - _Out_writes_(46) PWSTR S) + _Out_writes_(RTLIPV6A2S_MAX_LEN) PWSTR S) { - UNIMPLEMENTED; - return NULL; + NTSTATUS Status; + UINT Parts = 8, n; + BOOLEAN SkipOnce = TRUE; + PWSTR End; + size_t Remaining; + + if (!S) + return (PWSTR)~0; + + Remaining = RTLIPV6A2S_MAX_LEN; + /* does it look like an ipv4 address contained in an ipv6? http://tools.ietf.org/html/rfc2765 */ + if (!Addr->s6_words[0] && !Addr->s6_words[1] && !Addr->s6_words[2] && !Addr->s6_words[3] && Addr->s6_words[6]) + { + PWSTR Prefix = NULL; + if (Addr->s6_words[4] == 0xffff && !Addr->s6_words[5]) + Prefix = L"ffff:0:"; + else if (!Addr->s6_words[4] && Addr->s6_words[5] == 0xffff) + Prefix = L"ffff:"; + else if (!Addr->s6_words[4] && !Addr->s6_words[5]) + Prefix = L""; + if (Prefix != NULL) + { + Status = RtlStringCchPrintfExW(S, + Remaining, + &End, + NULL, + 0, + L"::%ls%u.%u.%u.%u", + Prefix, + Addr->s6_bytes[12], + Addr->s6_bytes[13], + Addr->s6_bytes[14], + Addr->s6_bytes[15]); + ASSERT(Status == STATUS_SUCCESS); + if (!NT_SUCCESS(Status)) + return (PWSTR)~0; + return End; + } + } + + /* does it look like an ISATAP address? http://tools.ietf.org/html/rfc5214 */ + if (!(Addr->s6_words[4] & 0xfffd) && Addr->s6_words[5] == 0xfe5e) + Parts = 6; + + for (n = 0; n < Parts; ++n) + { + if (SkipOnce && ((n + 1) < Parts) && !Addr->s6_words[n] && !Addr->s6_words[n + 1]) + { + SkipOnce = FALSE; + while (!Addr->s6_words[n + 1] && (n + 1) < Parts) + ++n; + *S++ = ':'; + Remaining--; + if ((n + 1) >= Parts) + { + *S++ = ':'; + Remaining--; + } + } + else + { + if (n) + { + *S++ = ':'; + Remaining--; + } + Status = RtlStringCchPrintfExW(S, + Remaining, + &End, + &Remaining, + 0, + L"%x", + WN2H(Addr->s6_words[n])); + ASSERT(Status == STATUS_SUCCESS); + if (!NT_SUCCESS(Status)) + return (PWSTR)~0; + S = End; + } + } + if (Parts < 8) + { + Status = RtlStringCchPrintfExW(S, + Remaining, + &End, + NULL, + 0, + L":%u.%u.%u.%u", + Addr->s6_bytes[12], + Addr->s6_bytes[13], + Addr->s6_bytes[14], + Addr->s6_bytes[15]); + ASSERT(Status == STATUS_SUCCESS); + if (!NT_SUCCESS(Status)) + return (PWSTR)~0; + + return End; + } + *S = UNICODE_NULL; + return S; } /* -* @unimplemented +* @implemented */ NTSTATUS NTAPI @@ -496,8 +630,68 @@ RtlIpv6AddressToStringExW( _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString, _Inout_ PULONG AddressStringLength) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN]; + PWCHAR S = Buffer; + NTSTATUS Status; + ULONG Length; + size_t Remaining; + + if (!Address || !AddressString || !AddressStringLength) + return STATUS_INVALID_PARAMETER; + + if (Port) + *S++ = L'['; + + S = RtlIpv6AddressToStringW(Address, S); + ASSERT(S != (PCWSTR)~0); + if (S == (PCWSTR)~0) + return STATUS_INVALID_PARAMETER; + + ASSERT(S >= Buffer); + ASSERT(S <= Buffer + RTLIPV6A2S_MAX_LEN + 1); + Remaining = RTL_NUMBER_OF(Buffer) - (S - Buffer); + ASSERT(Remaining >= RTLIPV6A2SEX_MAX_LEN - RTLIPV6A2S_MAX_LEN); + + if (ScopeId) + { + Status = RtlStringCchPrintfExW(S, + Remaining, + &S, + &Remaining, + 0, + L"%%%u", + ScopeId); + ASSERT(Status == STATUS_SUCCESS); + if (!NT_SUCCESS(Status)) + return STATUS_INVALID_PARAMETER; + } + + if (Port) + { + Status = RtlStringCchPrintfExW(S, + Remaining, + &S, + &Remaining, + 0, + L"]:%u", + WN2H(Port)); + ASSERT(Status == STATUS_SUCCESS); + if (!NT_SUCCESS(Status)) + return STATUS_INVALID_PARAMETER; + } + + Length = S - Buffer; + ASSERT(Buffer[Length] == UNICODE_NULL); + if (*AddressStringLength > Length) + { + Status = RtlStringCchCopyW(AddressString, *AddressStringLength, Buffer); + ASSERT(Status == STATUS_SUCCESS); + *AddressStringLength = Length + 1; + return STATUS_SUCCESS; + } + + *AddressStringLength = Length + 1; + return STATUS_INVALID_PARAMETER; } /*