4 * Copyright (C) 2003 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Some observations that an automated test can't produce:
23 * An adapter index is a key for an adapter. That is, if an index is returned
24 * from one API, that same index may be used successfully in another API, as
25 * long as the adapter remains present.
26 * If the adapter is removed and reinserted, however, the index may change (and
27 * indeed it does change on Win2K).
29 * The Name field of the IP_ADAPTER_INDEX_MAP entries returned by
30 * GetInterfaceInfo is declared as a wide string, but the bytes are actually
31 * an ASCII string on some versions of the IP helper API under Win9x. This was
32 * apparently an MS bug, it's corrected in later versions.
34 * The DomainName field of FIXED_INFO isn't NULL-terminated on Win98.
43 #include "wine/test.h"
47 static HMODULE hLibrary
= NULL
;
49 typedef DWORD (WINAPI
*GetNumberOfInterfacesFunc
)(PDWORD
);
50 typedef DWORD (WINAPI
*GetIpAddrTableFunc
)(PMIB_IPADDRTABLE
,PULONG
,BOOL
);
51 typedef DWORD (WINAPI
*GetIfEntryFunc
)(PMIB_IFROW
);
52 typedef DWORD (WINAPI
*GetFriendlyIfIndexFunc
)(DWORD
);
53 typedef DWORD (WINAPI
*GetIfTableFunc
)(PMIB_IFTABLE
,PULONG
,BOOL
);
54 typedef DWORD (WINAPI
*GetIpForwardTableFunc
)(PMIB_IPFORWARDTABLE
,PULONG
,BOOL
);
55 typedef DWORD (WINAPI
*GetIpNetTableFunc
)(PMIB_IPNETTABLE
,PULONG
,BOOL
);
56 typedef DWORD (WINAPI
*GetInterfaceInfoFunc
)(PIP_INTERFACE_INFO
,PULONG
);
57 typedef DWORD (WINAPI
*GetAdaptersInfoFunc
)(PIP_ADAPTER_INFO
,PULONG
);
58 typedef DWORD (WINAPI
*GetNetworkParamsFunc
)(PFIXED_INFO
,PULONG
);
59 typedef DWORD (WINAPI
*GetIcmpStatisticsFunc
)(PMIB_ICMP
);
60 typedef DWORD (WINAPI
*GetIpStatisticsFunc
)(PMIB_IPSTATS
);
61 typedef DWORD (WINAPI
*GetTcpStatisticsFunc
)(PMIB_TCPSTATS
);
62 typedef DWORD (WINAPI
*GetUdpStatisticsFunc
)(PMIB_UDPSTATS
);
63 typedef DWORD (WINAPI
*GetTcpTableFunc
)(PMIB_TCPTABLE
,PDWORD
,BOOL
);
64 typedef DWORD (WINAPI
*GetUdpTableFunc
)(PMIB_UDPTABLE
,PDWORD
,BOOL
);
65 typedef DWORD (WINAPI
*GetPerAdapterInfoFunc
)(ULONG
,PIP_PER_ADAPTER_INFO
,PULONG
);
66 typedef DWORD (WINAPI
*GetAdaptersAddressesFunc
)(ULONG
,ULONG
,PVOID
,PIP_ADAPTER_ADDRESSES
,PULONG
);
67 typedef DWORD (WINAPI
*NotifyAddrChangeFunc
)(PHANDLE
,LPOVERLAPPED
);
68 typedef BOOL (WINAPI
*CancelIPChangeNotifyFunc
)(LPOVERLAPPED
);
70 static GetNumberOfInterfacesFunc gGetNumberOfInterfaces
= NULL
;
71 static GetIpAddrTableFunc gGetIpAddrTable
= NULL
;
72 static GetIfEntryFunc gGetIfEntry
= NULL
;
73 static GetFriendlyIfIndexFunc gGetFriendlyIfIndex
= NULL
;
74 static GetIfTableFunc gGetIfTable
= NULL
;
75 static GetIpForwardTableFunc gGetIpForwardTable
= NULL
;
76 static GetIpNetTableFunc gGetIpNetTable
= NULL
;
77 static GetInterfaceInfoFunc gGetInterfaceInfo
= NULL
;
78 static GetAdaptersInfoFunc gGetAdaptersInfo
= NULL
;
79 static GetNetworkParamsFunc gGetNetworkParams
= NULL
;
80 static GetIcmpStatisticsFunc gGetIcmpStatistics
= NULL
;
81 static GetIpStatisticsFunc gGetIpStatistics
= NULL
;
82 static GetTcpStatisticsFunc gGetTcpStatistics
= NULL
;
83 static GetUdpStatisticsFunc gGetUdpStatistics
= NULL
;
84 static GetTcpTableFunc gGetTcpTable
= NULL
;
85 static GetUdpTableFunc gGetUdpTable
= NULL
;
86 static GetPerAdapterInfoFunc gGetPerAdapterInfo
= NULL
;
87 static GetAdaptersAddressesFunc gGetAdaptersAddresses
= NULL
;
88 static NotifyAddrChangeFunc gNotifyAddrChange
= NULL
;
89 static CancelIPChangeNotifyFunc gCancelIPChangeNotify
= NULL
;
91 static void loadIPHlpApi(void)
93 hLibrary
= LoadLibraryA("iphlpapi.dll");
95 gGetNumberOfInterfaces
= (GetNumberOfInterfacesFunc
)GetProcAddress(
96 hLibrary
, "GetNumberOfInterfaces");
97 gGetIpAddrTable
= (GetIpAddrTableFunc
)GetProcAddress(
98 hLibrary
, "GetIpAddrTable");
99 gGetIfEntry
= (GetIfEntryFunc
)GetProcAddress(
100 hLibrary
, "GetIfEntry");
101 gGetFriendlyIfIndex
= (GetFriendlyIfIndexFunc
)GetProcAddress(
102 hLibrary
, "GetFriendlyIfIndex");
103 gGetIfTable
= (GetIfTableFunc
)GetProcAddress(
104 hLibrary
, "GetIfTable");
105 gGetIpForwardTable
= (GetIpForwardTableFunc
)GetProcAddress(
106 hLibrary
, "GetIpForwardTable");
107 gGetIpNetTable
= (GetIpNetTableFunc
)GetProcAddress(
108 hLibrary
, "GetIpNetTable");
109 gGetInterfaceInfo
= (GetInterfaceInfoFunc
)GetProcAddress(
110 hLibrary
, "GetInterfaceInfo");
111 gGetAdaptersInfo
= (GetAdaptersInfoFunc
)GetProcAddress(
112 hLibrary
, "GetAdaptersInfo");
113 gGetNetworkParams
= (GetNetworkParamsFunc
)GetProcAddress(
114 hLibrary
, "GetNetworkParams");
115 gGetIcmpStatistics
= (GetIcmpStatisticsFunc
)GetProcAddress(
116 hLibrary
, "GetIcmpStatistics");
117 gGetIpStatistics
= (GetIpStatisticsFunc
)GetProcAddress(
118 hLibrary
, "GetIpStatistics");
119 gGetTcpStatistics
= (GetTcpStatisticsFunc
)GetProcAddress(
120 hLibrary
, "GetTcpStatistics");
121 gGetUdpStatistics
= (GetUdpStatisticsFunc
)GetProcAddress(
122 hLibrary
, "GetUdpStatistics");
123 gGetTcpTable
= (GetTcpTableFunc
)GetProcAddress(
124 hLibrary
, "GetTcpTable");
125 gGetUdpTable
= (GetUdpTableFunc
)GetProcAddress(
126 hLibrary
, "GetUdpTable");
127 gGetPerAdapterInfo
= (GetPerAdapterInfoFunc
)GetProcAddress(hLibrary
, "GetPerAdapterInfo");
128 gGetAdaptersAddresses
= (GetAdaptersAddressesFunc
)GetProcAddress(hLibrary
, "GetAdaptersAddresses");
129 gNotifyAddrChange
= (NotifyAddrChangeFunc
)GetProcAddress(
130 hLibrary
, "NotifyAddrChange");
131 gCancelIPChangeNotify
= (CancelIPChangeNotifyFunc
)GetProcAddress(
132 hLibrary
, "CancelIPChangeNotify");
136 static void freeIPHlpApi(void)
139 gGetNumberOfInterfaces
= NULL
;
140 gGetIpAddrTable
= NULL
;
142 gGetFriendlyIfIndex
= NULL
;
144 gGetIpForwardTable
= NULL
;
145 gGetIpNetTable
= NULL
;
146 gGetInterfaceInfo
= NULL
;
147 gGetAdaptersInfo
= NULL
;
148 gGetNetworkParams
= NULL
;
149 gGetIcmpStatistics
= NULL
;
150 gGetIpStatistics
= NULL
;
151 gGetTcpStatistics
= NULL
;
152 gGetUdpStatistics
= NULL
;
155 gNotifyAddrChange
= NULL
;
156 gCancelIPChangeNotify
= NULL
;
157 FreeLibrary(hLibrary
);
162 /* replacement for inet_ntoa */
163 static const char *ntoa( DWORD ip
)
165 static char buffer
[40];
168 sprintf( buffer
, "%u.%u.%u.%u", (ip
>> 24) & 0xff, (ip
>> 16) & 0xff, (ip
>> 8) & 0xff, ip
& 0xff );
173 still-to-be-tested 98-only functions:
174 GetUniDirectionalAdapterInfo
176 static void testWin98OnlyFunctions(void)
180 static void testGetNumberOfInterfaces(void)
182 if (gGetNumberOfInterfaces
) {
183 DWORD apiReturn
, numInterfaces
;
185 /* Crashes on Vista */
187 apiReturn
= gGetNumberOfInterfaces(NULL
);
188 if (apiReturn
== ERROR_NOT_SUPPORTED
)
190 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
191 "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
195 apiReturn
= gGetNumberOfInterfaces(&numInterfaces
);
196 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
197 skip("GetNumberOfInterfaces is not supported\n");
200 ok(apiReturn
== NO_ERROR
,
201 "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn
);
205 static void testGetIfEntry(DWORD index
)
211 memset(&row
, 0, sizeof(row
));
212 apiReturn
= gGetIfEntry(NULL
);
213 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
214 skip("GetIfEntry is not supported\n");
217 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
218 "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
220 row
.dwIndex
= -1; /* hope that's always bogus! */
221 apiReturn
= gGetIfEntry(&row
);
222 ok(apiReturn
== ERROR_INVALID_DATA
||
223 apiReturn
== ERROR_FILE_NOT_FOUND
/* Vista */,
224 "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n",
227 apiReturn
= gGetIfEntry(&row
);
228 ok(apiReturn
== NO_ERROR
,
229 "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn
);
233 static void testGetIpAddrTable(void)
235 if (gGetIpAddrTable
) {
239 apiReturn
= gGetIpAddrTable(NULL
, NULL
, FALSE
);
240 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
241 skip("GetIpAddrTable is not supported\n");
244 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
245 "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
247 apiReturn
= gGetIpAddrTable(NULL
, &dwSize
, FALSE
);
248 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
249 "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
251 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
252 PMIB_IPADDRTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
254 apiReturn
= gGetIpAddrTable(buf
, &dwSize
, FALSE
);
255 ok(apiReturn
== NO_ERROR
,
256 "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
258 if (apiReturn
== NO_ERROR
&& buf
->dwNumEntries
)
259 testGetIfEntry(buf
->table
[0].dwIndex
);
260 HeapFree(GetProcessHeap(), 0, buf
);
265 static void testGetIfTable(void)
271 apiReturn
= gGetIfTable(NULL
, NULL
, FALSE
);
272 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
273 skip("GetIfTable is not supported\n");
276 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
277 "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
279 apiReturn
= gGetIfTable(NULL
, &dwSize
, FALSE
);
280 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
281 "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
283 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
284 PMIB_IFTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
286 apiReturn
= gGetIfTable(buf
, &dwSize
, FALSE
);
287 ok(apiReturn
== NO_ERROR
,
288 "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n",
291 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
294 char name
[MAX_INTERFACE_NAME_LEN
];
296 trace( "interface table: %u entries\n", buf
->dwNumEntries
);
297 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
299 MIB_IFROW
*row
= &buf
->table
[i
];
300 WideCharToMultiByte( CP_ACP
, 0, row
->wszName
, -1, name
, MAX_INTERFACE_NAME_LEN
, NULL
, NULL
);
301 trace( "%u: '%s' type %u mtu %u speed %u phys",
302 row
->dwIndex
, name
, row
->dwType
, row
->dwMtu
, row
->dwSpeed
);
303 for (j
= 0; j
< row
->dwPhysAddrLen
; j
++)
304 printf( " %02x", row
->bPhysAddr
[j
] );
306 trace( " in: bytes %u upkts %u nupkts %u disc %u err %u unk %u\n",
307 row
->dwInOctets
, row
->dwInUcastPkts
, row
->dwInNUcastPkts
,
308 row
->dwInDiscards
, row
->dwInErrors
, row
->dwInUnknownProtos
);
309 trace( " out: bytes %u upkts %u nupkts %u disc %u err %u\n",
310 row
->dwOutOctets
, row
->dwOutUcastPkts
, row
->dwOutNUcastPkts
,
311 row
->dwOutDiscards
, row
->dwOutErrors
);
314 HeapFree(GetProcessHeap(), 0, buf
);
319 static void testGetIpForwardTable(void)
321 if (gGetIpForwardTable
) {
325 apiReturn
= gGetIpForwardTable(NULL
, NULL
, FALSE
);
326 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
327 skip("GetIpForwardTable is not supported\n");
330 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
331 "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
333 apiReturn
= gGetIpForwardTable(NULL
, &dwSize
, FALSE
);
334 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
335 "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
337 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
338 PMIB_IPFORWARDTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
340 apiReturn
= gGetIpForwardTable(buf
, &dwSize
, FALSE
);
341 ok(apiReturn
== NO_ERROR
,
342 "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
345 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
349 trace( "IP forward table: %u entries\n", buf
->dwNumEntries
);
350 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
353 sprintf( buffer
, "dest %s", ntoa( buf
->table
[i
].dwForwardDest
));
354 sprintf( buffer
+ strlen(buffer
), " mask %s", ntoa( buf
->table
[i
].dwForwardMask
));
355 trace( "%u: %s gw %s if %u type %u\n", i
, buffer
,
356 ntoa( buf
->table
[i
].dwForwardNextHop
),
357 buf
->table
[i
].dwForwardIfIndex
, U1(buf
->table
[i
]).dwForwardType
);
360 HeapFree(GetProcessHeap(), 0, buf
);
365 static void testGetIpNetTable(void)
367 if (gGetIpNetTable
) {
371 apiReturn
= gGetIpNetTable(NULL
, NULL
, FALSE
);
372 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
373 skip("GetIpNetTable is not supported\n");
376 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
377 "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
379 apiReturn
= gGetIpNetTable(NULL
, &dwSize
, FALSE
);
380 ok(apiReturn
== ERROR_NO_DATA
|| apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
381 "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n",
383 if (apiReturn
== ERROR_NO_DATA
)
384 ; /* empty ARP table's okay */
385 else if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
386 PMIB_IPNETTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
388 apiReturn
= gGetIpNetTable(buf
, &dwSize
, FALSE
);
389 ok(apiReturn
== NO_ERROR
||
390 apiReturn
== ERROR_NO_DATA
, /* empty ARP table's okay */
391 "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
394 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
398 trace( "IP net table: %u entries\n", buf
->dwNumEntries
);
399 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
401 trace( "%u: idx %u type %u addr %s phys",
402 i
, buf
->table
[i
].dwIndex
, U(buf
->table
[i
]).dwType
, ntoa( buf
->table
[i
].dwAddr
));
403 for (j
= 0; j
< buf
->table
[i
].dwPhysAddrLen
; j
++)
404 printf( " %02x", buf
->table
[i
].bPhysAddr
[j
] );
408 HeapFree(GetProcessHeap(), 0, buf
);
413 static void testGetIcmpStatistics(void)
415 if (gGetIcmpStatistics
) {
419 /* Crashes on Vista */
421 apiReturn
= gGetIcmpStatistics(NULL
);
422 if (apiReturn
== ERROR_NOT_SUPPORTED
)
424 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
425 "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
429 apiReturn
= gGetIcmpStatistics(&stats
);
430 if (apiReturn
== ERROR_NOT_SUPPORTED
)
432 skip("GetIcmpStatistics is not supported\n");
435 ok(apiReturn
== NO_ERROR
,
436 "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
437 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
439 trace( "ICMP stats: %8s %8s\n", "in", "out" );
440 trace( " dwMsgs: %8u %8u\n", stats
.stats
.icmpInStats
.dwMsgs
, stats
.stats
.icmpOutStats
.dwMsgs
);
441 trace( " dwErrors: %8u %8u\n", stats
.stats
.icmpInStats
.dwErrors
, stats
.stats
.icmpOutStats
.dwErrors
);
442 trace( " dwDestUnreachs: %8u %8u\n", stats
.stats
.icmpInStats
.dwDestUnreachs
, stats
.stats
.icmpOutStats
.dwDestUnreachs
);
443 trace( " dwTimeExcds: %8u %8u\n", stats
.stats
.icmpInStats
.dwTimeExcds
, stats
.stats
.icmpOutStats
.dwTimeExcds
);
444 trace( " dwParmProbs: %8u %8u\n", stats
.stats
.icmpInStats
.dwParmProbs
, stats
.stats
.icmpOutStats
.dwParmProbs
);
445 trace( " dwSrcQuenchs: %8u %8u\n", stats
.stats
.icmpInStats
.dwSrcQuenchs
, stats
.stats
.icmpOutStats
.dwSrcQuenchs
);
446 trace( " dwRedirects: %8u %8u\n", stats
.stats
.icmpInStats
.dwRedirects
, stats
.stats
.icmpOutStats
.dwRedirects
);
447 trace( " dwEchos: %8u %8u\n", stats
.stats
.icmpInStats
.dwEchos
, stats
.stats
.icmpOutStats
.dwEchos
);
448 trace( " dwEchoReps: %8u %8u\n", stats
.stats
.icmpInStats
.dwEchoReps
, stats
.stats
.icmpOutStats
.dwEchoReps
);
449 trace( " dwTimestamps: %8u %8u\n", stats
.stats
.icmpInStats
.dwTimestamps
, stats
.stats
.icmpOutStats
.dwTimestamps
);
450 trace( " dwTimestampReps: %8u %8u\n", stats
.stats
.icmpInStats
.dwTimestampReps
, stats
.stats
.icmpOutStats
.dwTimestampReps
);
451 trace( " dwAddrMasks: %8u %8u\n", stats
.stats
.icmpInStats
.dwAddrMasks
, stats
.stats
.icmpOutStats
.dwAddrMasks
);
452 trace( " dwAddrMaskReps: %8u %8u\n", stats
.stats
.icmpInStats
.dwAddrMaskReps
, stats
.stats
.icmpOutStats
.dwAddrMaskReps
);
457 static void testGetIpStatistics(void)
459 if (gGetIpStatistics
) {
463 apiReturn
= gGetIpStatistics(NULL
);
464 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
465 skip("GetIpStatistics is not supported\n");
468 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
469 "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
471 apiReturn
= gGetIpStatistics(&stats
);
472 ok(apiReturn
== NO_ERROR
,
473 "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
474 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
476 trace( "IP stats:\n" );
477 trace( " dwForwarding: %u\n", U(stats
).dwForwarding
);
478 trace( " dwDefaultTTL: %u\n", stats
.dwDefaultTTL
);
479 trace( " dwInReceives: %u\n", stats
.dwInReceives
);
480 trace( " dwInHdrErrors: %u\n", stats
.dwInHdrErrors
);
481 trace( " dwInAddrErrors: %u\n", stats
.dwInAddrErrors
);
482 trace( " dwForwDatagrams: %u\n", stats
.dwForwDatagrams
);
483 trace( " dwInUnknownProtos: %u\n", stats
.dwInUnknownProtos
);
484 trace( " dwInDiscards: %u\n", stats
.dwInDiscards
);
485 trace( " dwInDelivers: %u\n", stats
.dwInDelivers
);
486 trace( " dwOutRequests: %u\n", stats
.dwOutRequests
);
487 trace( " dwRoutingDiscards: %u\n", stats
.dwRoutingDiscards
);
488 trace( " dwOutDiscards: %u\n", stats
.dwOutDiscards
);
489 trace( " dwOutNoRoutes: %u\n", stats
.dwOutNoRoutes
);
490 trace( " dwReasmTimeout: %u\n", stats
.dwReasmTimeout
);
491 trace( " dwReasmReqds: %u\n", stats
.dwReasmReqds
);
492 trace( " dwReasmOks: %u\n", stats
.dwReasmOks
);
493 trace( " dwReasmFails: %u\n", stats
.dwReasmFails
);
494 trace( " dwFragOks: %u\n", stats
.dwFragOks
);
495 trace( " dwFragFails: %u\n", stats
.dwFragFails
);
496 trace( " dwFragCreates: %u\n", stats
.dwFragCreates
);
497 trace( " dwNumIf: %u\n", stats
.dwNumIf
);
498 trace( " dwNumAddr: %u\n", stats
.dwNumAddr
);
499 trace( " dwNumRoutes: %u\n", stats
.dwNumRoutes
);
504 static void testGetTcpStatistics(void)
506 if (gGetTcpStatistics
) {
510 apiReturn
= gGetTcpStatistics(NULL
);
511 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
512 skip("GetTcpStatistics is not supported\n");
515 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
516 "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
518 apiReturn
= gGetTcpStatistics(&stats
);
519 ok(apiReturn
== NO_ERROR
,
520 "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
521 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
523 trace( "TCP stats:\n" );
524 trace( " dwRtoAlgorithm: %u\n", U(stats
).dwRtoAlgorithm
);
525 trace( " dwRtoMin: %u\n", stats
.dwRtoMin
);
526 trace( " dwRtoMax: %u\n", stats
.dwRtoMax
);
527 trace( " dwMaxConn: %u\n", stats
.dwMaxConn
);
528 trace( " dwActiveOpens: %u\n", stats
.dwActiveOpens
);
529 trace( " dwPassiveOpens: %u\n", stats
.dwPassiveOpens
);
530 trace( " dwAttemptFails: %u\n", stats
.dwAttemptFails
);
531 trace( " dwEstabResets: %u\n", stats
.dwEstabResets
);
532 trace( " dwCurrEstab: %u\n", stats
.dwCurrEstab
);
533 trace( " dwInSegs: %u\n", stats
.dwInSegs
);
534 trace( " dwOutSegs: %u\n", stats
.dwOutSegs
);
535 trace( " dwRetransSegs: %u\n", stats
.dwRetransSegs
);
536 trace( " dwInErrs: %u\n", stats
.dwInErrs
);
537 trace( " dwOutRsts: %u\n", stats
.dwOutRsts
);
538 trace( " dwNumConns: %u\n", stats
.dwNumConns
);
543 static void testGetUdpStatistics(void)
545 if (gGetUdpStatistics
) {
549 apiReturn
= gGetUdpStatistics(NULL
);
550 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
551 skip("GetUdpStatistics is not supported\n");
554 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
555 "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
557 apiReturn
= gGetUdpStatistics(&stats
);
558 ok(apiReturn
== NO_ERROR
,
559 "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
560 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
562 trace( "UDP stats:\n" );
563 trace( " dwInDatagrams: %u\n", stats
.dwInDatagrams
);
564 trace( " dwNoPorts: %u\n", stats
.dwNoPorts
);
565 trace( " dwInErrors: %u\n", stats
.dwInErrors
);
566 trace( " dwOutDatagrams: %u\n", stats
.dwOutDatagrams
);
567 trace( " dwNumAddrs: %u\n", stats
.dwNumAddrs
);
572 static void testGetTcpTable(void)
578 apiReturn
= gGetTcpTable(NULL
, &dwSize
, FALSE
);
579 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
580 skip("GetTcpTable is not supported\n");
583 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
||
584 broken(apiReturn
== ERROR_NO_DATA
), /* win95 */
585 "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
587 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
588 PMIB_TCPTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
590 apiReturn
= gGetTcpTable(buf
, &dwSize
, FALSE
);
591 ok(apiReturn
== NO_ERROR
,
592 "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
595 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
598 trace( "TCP table: %u entries\n", buf
->dwNumEntries
);
599 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
602 sprintf( buffer
, "local %s:%u",
603 ntoa(buf
->table
[i
].dwLocalAddr
), ntohs(buf
->table
[i
].dwLocalPort
) );
604 trace( "%u: %s remote %s:%u state %u\n",
605 i
, buffer
, ntoa( buf
->table
[i
].dwRemoteAddr
),
606 ntohs(buf
->table
[i
].dwRemotePort
), U(buf
->table
[i
]).dwState
);
609 HeapFree(GetProcessHeap(), 0, buf
);
614 static void testGetUdpTable(void)
620 apiReturn
= gGetUdpTable(NULL
, &dwSize
, FALSE
);
621 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
622 skip("GetUdpTable is not supported\n");
625 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
626 "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
628 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
629 PMIB_UDPTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
631 apiReturn
= gGetUdpTable(buf
, &dwSize
, FALSE
);
632 ok(apiReturn
== NO_ERROR
,
633 "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
636 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
639 trace( "UDP table: %u entries\n", buf
->dwNumEntries
);
640 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
641 trace( "%u: %s:%u\n",
642 i
, ntoa( buf
->table
[i
].dwLocalAddr
), ntohs(buf
->table
[i
].dwLocalPort
) );
644 HeapFree(GetProcessHeap(), 0, buf
);
650 still-to-be-tested NT4-onward functions:
664 static void testWinNT4Functions(void)
666 testGetNumberOfInterfaces();
667 testGetIpAddrTable();
669 testGetIpForwardTable();
671 testGetIcmpStatistics();
672 testGetIpStatistics();
673 testGetTcpStatistics();
674 testGetUdpStatistics();
679 static void testGetInterfaceInfo(void)
681 if (gGetInterfaceInfo
) {
685 apiReturn
= gGetInterfaceInfo(NULL
, NULL
);
686 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
687 skip("GetInterfaceInfo is not supported\n");
690 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
691 "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
693 apiReturn
= gGetInterfaceInfo(NULL
, &len
);
694 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
695 "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
697 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
698 PIP_INTERFACE_INFO buf
= HeapAlloc(GetProcessHeap(), 0, len
);
700 apiReturn
= gGetInterfaceInfo(buf
, &len
);
701 ok(apiReturn
== NO_ERROR
,
702 "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
704 HeapFree(GetProcessHeap(), 0, buf
);
709 static void testGetAdaptersInfo(void)
711 if (gGetAdaptersInfo
) {
715 apiReturn
= gGetAdaptersInfo(NULL
, NULL
);
716 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
717 skip("GetAdaptersInfo is not supported\n");
720 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
721 "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
723 apiReturn
= gGetAdaptersInfo(NULL
, &len
);
724 ok(apiReturn
== ERROR_NO_DATA
|| apiReturn
== ERROR_BUFFER_OVERFLOW
,
725 "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n",
727 if (apiReturn
== ERROR_NO_DATA
)
728 ; /* no adapter's, that's okay */
729 else if (apiReturn
== ERROR_BUFFER_OVERFLOW
) {
730 PIP_ADAPTER_INFO buf
= HeapAlloc(GetProcessHeap(), 0, len
);
732 apiReturn
= gGetAdaptersInfo(buf
, &len
);
733 ok(apiReturn
== NO_ERROR
,
734 "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
736 HeapFree(GetProcessHeap(), 0, buf
);
741 static void testGetNetworkParams(void)
743 if (gGetNetworkParams
) {
747 apiReturn
= gGetNetworkParams(NULL
, NULL
);
748 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
749 skip("GetNetworkParams is not supported\n");
752 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
753 "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n",
755 apiReturn
= gGetNetworkParams(NULL
, &len
);
756 ok(apiReturn
== ERROR_BUFFER_OVERFLOW
,
757 "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n",
759 if (apiReturn
== ERROR_BUFFER_OVERFLOW
) {
760 PFIXED_INFO buf
= HeapAlloc(GetProcessHeap(), 0, len
);
762 apiReturn
= gGetNetworkParams(buf
, &len
);
763 ok(apiReturn
== NO_ERROR
,
764 "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n",
766 HeapFree(GetProcessHeap(), 0, buf
);
772 still-to-be-tested 98-onward functions:
778 static DWORD CALLBACK
testWin98Functions(void *p
)
780 testGetInterfaceInfo();
781 testGetAdaptersInfo();
782 testGetNetworkParams();
786 static void testGetPerAdapterInfo(void)
791 if (!gGetPerAdapterInfo
) return;
792 ret
= gGetPerAdapterInfo(1, NULL
, NULL
);
793 if (ret
== ERROR_NOT_SUPPORTED
) {
794 skip("GetPerAdapterInfo is not supported\n");
797 ok( ret
== ERROR_INVALID_PARAMETER
, "got %u instead of ERROR_INVALID_PARAMETER\n", ret
);
799 ret
= gGetPerAdapterInfo(1, NULL
, &needed
);
800 if (ret
== ERROR_NO_DATA
) return; /* no such adapter */
801 ok( ret
== ERROR_BUFFER_OVERFLOW
, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret
);
802 ok( needed
!= 0xdeadbeef, "needed not set\n" );
803 buffer
= HeapAlloc( GetProcessHeap(), 0, needed
);
804 ret
= gGetPerAdapterInfo(1, buffer
, &needed
);
805 ok( ret
== NO_ERROR
, "got %u instead of NO_ERROR\n", ret
);
806 HeapFree( GetProcessHeap(), 0, buffer
);
809 static void testNotifyAddrChange(void)
812 OVERLAPPED overlapped
;
816 if (!gNotifyAddrChange
)
818 win_skip("NotifyAddrChange not present\n");
821 if (!gCancelIPChangeNotify
)
823 win_skip("CancelIPChangeNotify not present\n");
828 ZeroMemory(&overlapped
, sizeof(overlapped
));
829 ret
= gNotifyAddrChange(&handle
, &overlapped
);
830 if (ret
== ERROR_NOT_SUPPORTED
)
832 win_skip("NotifyAddrChange is not supported\n");
835 ok(ret
== ERROR_IO_PENDING
, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret
);
836 ret
= GetLastError();
837 todo_wine
ok(ret
== ERROR_IO_PENDING
, "GetLastError returned %d, expected ERROR_IO_PENDING\n", ret
);
838 success
= gCancelIPChangeNotify(&overlapped
);
839 todo_wine
ok(success
== TRUE
, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
841 ZeroMemory(&overlapped
, sizeof(overlapped
));
842 success
= gCancelIPChangeNotify(&overlapped
);
843 ok(success
== FALSE
, "CancelIPChangeNotify returned TRUE, expected FALSE\n");
846 ZeroMemory(&overlapped
, sizeof(overlapped
));
847 overlapped
.hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
848 ret
= gNotifyAddrChange(&handle
, &overlapped
);
849 ok(ret
== ERROR_IO_PENDING
, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret
);
850 todo_wine
ok(handle
!= INVALID_HANDLE_VALUE
, "NotifyAddrChange returned invalid file handle\n");
851 success
= GetOverlappedResult(handle
, &overlapped
, &bytes
, FALSE
);
852 ok(success
== FALSE
, "GetOverlappedResult returned TRUE, expected FALSE\n");
853 ret
= GetLastError();
854 ok(ret
== ERROR_IO_INCOMPLETE
, "GetLastError returned %d, expected ERROR_IO_INCOMPLETE\n", ret
);
855 success
= gCancelIPChangeNotify(&overlapped
);
856 todo_wine
ok(success
== TRUE
, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
858 if (winetest_interactive
)
861 ZeroMemory(&overlapped
, sizeof(overlapped
));
862 overlapped
.hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
863 trace("Testing asynchronous ipv4 address change notification. Please "
864 "change the ipv4 address of one of your network interfaces\n");
865 ret
= gNotifyAddrChange(&handle
, &overlapped
);
866 ok(ret
== ERROR_IO_PENDING
, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret
);
867 success
= GetOverlappedResult(handle
, &overlapped
, &bytes
, TRUE
);
868 ok(success
== TRUE
, "GetOverlappedResult returned FALSE, expected TRUE\n");
871 /* test synchronous functionality */
872 if (winetest_interactive
)
874 trace("Testing synchronous ipv4 address change notification. Please "
875 "change the ipv4 address of one of your network interfaces\n");
876 ret
= gNotifyAddrChange(NULL
, NULL
);
877 todo_wine
ok(ret
== NO_ERROR
, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret
);
882 still-to-be-tested 2K-onward functions:
890 NotifyRouteChange + CancelIPChangeNotify
894 static void testWin2KFunctions(void)
896 testGetPerAdapterInfo();
897 testNotifyAddrChange();
900 static void test_GetAdaptersAddresses(void)
903 IP_ADAPTER_ADDRESSES
*aa
, *ptr
;
904 IP_ADAPTER_UNICAST_ADDRESS
*ua
;
906 if (!gGetAdaptersAddresses
)
908 win_skip("GetAdaptersAddresses not present\n");
912 ret
= gGetAdaptersAddresses(AF_UNSPEC
, 0, NULL
, NULL
, NULL
);
913 ok(ret
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER got %u\n", ret
);
915 /* size should be ignored and overwritten if buffer is NULL */
917 ret
= gGetAdaptersAddresses(AF_UNSPEC
, 0, NULL
, NULL
, &size
);
918 ok(ret
== ERROR_BUFFER_OVERFLOW
, "expected ERROR_BUFFER_OVERFLOW, got %u\n", ret
);
919 if (ret
!= ERROR_BUFFER_OVERFLOW
) return;
921 ptr
= HeapAlloc(GetProcessHeap(), 0, size
);
922 ret
= gGetAdaptersAddresses(AF_UNSPEC
, 0, NULL
, ptr
, &size
);
923 ok(!ret
, "expected ERROR_SUCCESS got %u\n", ret
);
925 for (aa
= ptr
; !ret
&& aa
; aa
= aa
->Next
)
927 ok(aa
->DnsSuffix
!= NULL
, "DnsSuffix is not a valid pointer\n");
928 ok(aa
->Description
!= NULL
, "Description is not a valid pointer\n");
929 ok(aa
->FriendlyName
!= NULL
, "FriendlyName is not a valid pointer\n");
931 if (winetest_debug
<= 1)
934 trace("Length: %u\n", S(U(*aa
)).Length
);
935 trace("IfIndex: %u\n", S(U(*aa
)).IfIndex
);
936 trace("Next: %p\n", aa
->Next
);
937 trace("AdapterName: %s\n", aa
->AdapterName
);
938 trace("FirstUnicastAddress: %p\n", aa
->FirstUnicastAddress
);
939 ua
= aa
->FirstUnicastAddress
;
942 trace("\tLength: %u\n", S(U(*ua
)).Length
);
943 trace("\tFlags: 0x%08x\n", S(U(*ua
)).Flags
);
944 trace("\tNext: %p\n", ua
->Next
);
945 trace("\tAddress.lpSockaddr: %p\n", ua
->Address
.lpSockaddr
);
946 trace("\tAddress.iSockaddrLength: %d\n", ua
->Address
.iSockaddrLength
);
947 trace("\tPrefixOrigin: %u\n", ua
->PrefixOrigin
);
948 trace("\tSuffixOrigin: %u\n", ua
->SuffixOrigin
);
949 trace("\tDadState: %u\n", ua
->DadState
);
950 trace("\tValidLifetime: 0x%08x\n", ua
->ValidLifetime
);
951 trace("\tPreferredLifetime: 0x%08x\n", ua
->PreferredLifetime
);
952 trace("\tLeaseLifetime: 0x%08x\n", ua
->LeaseLifetime
);
956 trace("FirstAnycastAddress: %p\n", aa
->FirstAnycastAddress
);
957 trace("FirstMulticastAddress: %p\n", aa
->FirstMulticastAddress
);
958 trace("FirstDnsServerAddress: %p\n", aa
->FirstDnsServerAddress
);
959 trace("DnsSuffix: %p\n", aa
->DnsSuffix
);
960 trace("Description: %p\n", aa
->Description
);
961 trace("FriendlyName: %p\n", aa
->FriendlyName
);
962 trace("PhysicalAddress: %02x\n", aa
->PhysicalAddress
[0]);
963 trace("PhysicalAddressLength: %u\n", aa
->PhysicalAddressLength
);
964 trace("Flags: 0x%08x\n", aa
->Flags
);
965 trace("Mtu: %u\n", aa
->Mtu
);
966 trace("IfType: %u\n", aa
->IfType
);
967 trace("OperStatus: %u\n", aa
->OperStatus
);
970 HeapFree(GetProcessHeap(), 0, ptr
);
980 testWin98OnlyFunctions();
981 testWinNT4Functions();
983 /* run testGetXXXX in two threads at once to make sure we don't crash in that case */
984 thread
= CreateThread(NULL
, 0, testWin98Functions
, NULL
, 0, NULL
);
985 testWin98Functions(NULL
);
986 WaitForSingleObject(thread
, INFINITE
);
988 testWin2KFunctions();
989 test_GetAdaptersAddresses();