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"
52 #define htonl(l) ((u_long)(l))
53 #define htons(s) ((u_short)(s))
54 #define ntohl(l) ((u_long)(l))
55 #define ntohs(s) ((u_short)(s))
57 static HMODULE hLibrary
= NULL
;
59 typedef DWORD (WINAPI
*GetNumberOfInterfacesFunc
)(PDWORD
);
60 typedef DWORD (WINAPI
*GetIpAddrTableFunc
)(PMIB_IPADDRTABLE
,PULONG
,BOOL
);
61 typedef DWORD (WINAPI
*GetIfEntryFunc
)(PMIB_IFROW
);
62 typedef DWORD (WINAPI
*GetFriendlyIfIndexFunc
)(DWORD
);
63 typedef DWORD (WINAPI
*GetIfTableFunc
)(PMIB_IFTABLE
,PULONG
,BOOL
);
64 typedef DWORD (WINAPI
*GetIpForwardTableFunc
)(PMIB_IPFORWARDTABLE
,PULONG
,BOOL
);
65 typedef DWORD (WINAPI
*GetIpNetTableFunc
)(PMIB_IPNETTABLE
,PULONG
,BOOL
);
66 typedef DWORD (WINAPI
*GetInterfaceInfoFunc
)(PIP_INTERFACE_INFO
,PULONG
);
67 typedef DWORD (WINAPI
*GetAdaptersInfoFunc
)(PIP_ADAPTER_INFO
,PULONG
);
68 typedef DWORD (WINAPI
*GetNetworkParamsFunc
)(PFIXED_INFO
,PULONG
);
69 typedef DWORD (WINAPI
*GetIcmpStatisticsFunc
)(PMIB_ICMP
);
70 typedef DWORD (WINAPI
*GetIpStatisticsFunc
)(PMIB_IPSTATS
);
71 typedef DWORD (WINAPI
*GetTcpStatisticsFunc
)(PMIB_TCPSTATS
);
72 typedef DWORD (WINAPI
*GetUdpStatisticsFunc
)(PMIB_UDPSTATS
);
73 typedef DWORD (WINAPI
*GetTcpTableFunc
)(PMIB_TCPTABLE
,PDWORD
,BOOL
);
74 typedef DWORD (WINAPI
*GetUdpTableFunc
)(PMIB_UDPTABLE
,PDWORD
,BOOL
);
75 typedef DWORD (WINAPI
*GetPerAdapterInfoFunc
)(ULONG
,PIP_PER_ADAPTER_INFO
,PULONG
);
76 typedef DWORD (WINAPI
*GetAdaptersAddressesFunc
)(ULONG
,ULONG
,PVOID
,PIP_ADAPTER_ADDRESSES
,PULONG
);
77 typedef DWORD (WINAPI
*NotifyAddrChangeFunc
)(PHANDLE
,LPOVERLAPPED
);
78 typedef BOOL (WINAPI
*CancelIPChangeNotifyFunc
)(LPOVERLAPPED
);
80 static GetNumberOfInterfacesFunc gGetNumberOfInterfaces
= NULL
;
81 static GetIpAddrTableFunc gGetIpAddrTable
= NULL
;
82 static GetIfEntryFunc gGetIfEntry
= NULL
;
83 static GetFriendlyIfIndexFunc gGetFriendlyIfIndex
= NULL
;
84 static GetIfTableFunc gGetIfTable
= NULL
;
85 static GetIpForwardTableFunc gGetIpForwardTable
= NULL
;
86 static GetIpNetTableFunc gGetIpNetTable
= NULL
;
87 static GetInterfaceInfoFunc gGetInterfaceInfo
= NULL
;
88 static GetAdaptersInfoFunc gGetAdaptersInfo
= NULL
;
89 static GetNetworkParamsFunc gGetNetworkParams
= NULL
;
90 static GetIcmpStatisticsFunc gGetIcmpStatistics
= NULL
;
91 static GetIpStatisticsFunc gGetIpStatistics
= NULL
;
92 static GetTcpStatisticsFunc gGetTcpStatistics
= NULL
;
93 static GetUdpStatisticsFunc gGetUdpStatistics
= NULL
;
94 static GetTcpTableFunc gGetTcpTable
= NULL
;
95 static GetUdpTableFunc gGetUdpTable
= NULL
;
96 static GetPerAdapterInfoFunc gGetPerAdapterInfo
= NULL
;
97 static GetAdaptersAddressesFunc gGetAdaptersAddresses
= NULL
;
98 static NotifyAddrChangeFunc gNotifyAddrChange
= NULL
;
99 static CancelIPChangeNotifyFunc gCancelIPChangeNotify
= NULL
;
101 static void loadIPHlpApi(void)
103 hLibrary
= LoadLibraryA("iphlpapi.dll");
105 gGetNumberOfInterfaces
= (GetNumberOfInterfacesFunc
)GetProcAddress(
106 hLibrary
, "GetNumberOfInterfaces");
107 gGetIpAddrTable
= (GetIpAddrTableFunc
)GetProcAddress(
108 hLibrary
, "GetIpAddrTable");
109 gGetIfEntry
= (GetIfEntryFunc
)GetProcAddress(
110 hLibrary
, "GetIfEntry");
111 gGetFriendlyIfIndex
= (GetFriendlyIfIndexFunc
)GetProcAddress(
112 hLibrary
, "GetFriendlyIfIndex");
113 gGetIfTable
= (GetIfTableFunc
)GetProcAddress(
114 hLibrary
, "GetIfTable");
115 gGetIpForwardTable
= (GetIpForwardTableFunc
)GetProcAddress(
116 hLibrary
, "GetIpForwardTable");
117 gGetIpNetTable
= (GetIpNetTableFunc
)GetProcAddress(
118 hLibrary
, "GetIpNetTable");
119 gGetInterfaceInfo
= (GetInterfaceInfoFunc
)GetProcAddress(
120 hLibrary
, "GetInterfaceInfo");
121 gGetAdaptersInfo
= (GetAdaptersInfoFunc
)GetProcAddress(
122 hLibrary
, "GetAdaptersInfo");
123 gGetNetworkParams
= (GetNetworkParamsFunc
)GetProcAddress(
124 hLibrary
, "GetNetworkParams");
125 gGetIcmpStatistics
= (GetIcmpStatisticsFunc
)GetProcAddress(
126 hLibrary
, "GetIcmpStatistics");
127 gGetIpStatistics
= (GetIpStatisticsFunc
)GetProcAddress(
128 hLibrary
, "GetIpStatistics");
129 gGetTcpStatistics
= (GetTcpStatisticsFunc
)GetProcAddress(
130 hLibrary
, "GetTcpStatistics");
131 gGetUdpStatistics
= (GetUdpStatisticsFunc
)GetProcAddress(
132 hLibrary
, "GetUdpStatistics");
133 gGetTcpTable
= (GetTcpTableFunc
)GetProcAddress(
134 hLibrary
, "GetTcpTable");
135 gGetUdpTable
= (GetUdpTableFunc
)GetProcAddress(
136 hLibrary
, "GetUdpTable");
137 gGetPerAdapterInfo
= (GetPerAdapterInfoFunc
)GetProcAddress(hLibrary
, "GetPerAdapterInfo");
138 gGetAdaptersAddresses
= (GetAdaptersAddressesFunc
)GetProcAddress(hLibrary
, "GetAdaptersAddresses");
139 gNotifyAddrChange
= (NotifyAddrChangeFunc
)GetProcAddress(
140 hLibrary
, "NotifyAddrChange");
141 gCancelIPChangeNotify
= (CancelIPChangeNotifyFunc
)GetProcAddress(
142 hLibrary
, "CancelIPChangeNotify");
146 static void freeIPHlpApi(void)
149 gGetNumberOfInterfaces
= NULL
;
150 gGetIpAddrTable
= NULL
;
152 gGetFriendlyIfIndex
= NULL
;
154 gGetIpForwardTable
= NULL
;
155 gGetIpNetTable
= NULL
;
156 gGetInterfaceInfo
= NULL
;
157 gGetAdaptersInfo
= NULL
;
158 gGetNetworkParams
= NULL
;
159 gGetIcmpStatistics
= NULL
;
160 gGetIpStatistics
= NULL
;
161 gGetTcpStatistics
= NULL
;
162 gGetUdpStatistics
= NULL
;
165 gNotifyAddrChange
= NULL
;
166 gCancelIPChangeNotify
= NULL
;
167 FreeLibrary(hLibrary
);
172 /* replacement for inet_ntoa */
173 static const char *ntoa( DWORD ip
)
175 static char buffer
[40];
178 sprintf( buffer
, "%u.%u.%u.%u", (ip
>> 24) & 0xff, (ip
>> 16) & 0xff, (ip
>> 8) & 0xff, ip
& 0xff );
183 still-to-be-tested 98-only functions:
184 GetUniDirectionalAdapterInfo
186 static void testWin98OnlyFunctions(void)
190 static void testGetNumberOfInterfaces(void)
192 if (gGetNumberOfInterfaces
) {
193 DWORD apiReturn
, numInterfaces
;
195 /* Crashes on Vista */
197 apiReturn
= gGetNumberOfInterfaces(NULL
);
198 if (apiReturn
== ERROR_NOT_SUPPORTED
)
200 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
201 "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
205 apiReturn
= gGetNumberOfInterfaces(&numInterfaces
);
206 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
207 skip("GetNumberOfInterfaces is not supported\n");
210 ok(apiReturn
== NO_ERROR
,
211 "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn
);
215 static void testGetIfEntry(DWORD index
)
221 memset(&row
, 0, sizeof(row
));
222 apiReturn
= gGetIfEntry(NULL
);
223 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
224 skip("GetIfEntry is not supported\n");
227 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
228 "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
230 row
.dwIndex
= -1; /* hope that's always bogus! */
231 apiReturn
= gGetIfEntry(&row
);
232 ok(apiReturn
== ERROR_INVALID_DATA
||
233 apiReturn
== ERROR_FILE_NOT_FOUND
/* Vista */,
234 "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n",
237 apiReturn
= gGetIfEntry(&row
);
238 ok(apiReturn
== NO_ERROR
,
239 "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn
);
243 static void testGetIpAddrTable(void)
245 if (gGetIpAddrTable
) {
249 apiReturn
= gGetIpAddrTable(NULL
, NULL
, FALSE
);
250 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
251 skip("GetIpAddrTable is not supported\n");
254 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
255 "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
257 apiReturn
= gGetIpAddrTable(NULL
, &dwSize
, FALSE
);
258 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
259 "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
261 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
262 PMIB_IPADDRTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
264 apiReturn
= gGetIpAddrTable(buf
, &dwSize
, FALSE
);
265 ok(apiReturn
== NO_ERROR
,
266 "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
268 if (apiReturn
== NO_ERROR
&& buf
->dwNumEntries
)
269 testGetIfEntry(buf
->table
[0].dwIndex
);
270 HeapFree(GetProcessHeap(), 0, buf
);
275 static void testGetIfTable(void)
281 apiReturn
= gGetIfTable(NULL
, NULL
, FALSE
);
282 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
283 skip("GetIfTable is not supported\n");
286 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
287 "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
289 apiReturn
= gGetIfTable(NULL
, &dwSize
, FALSE
);
290 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
291 "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
293 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
294 PMIB_IFTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
296 apiReturn
= gGetIfTable(buf
, &dwSize
, FALSE
);
297 ok(apiReturn
== NO_ERROR
,
298 "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n",
301 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
304 char name
[MAX_INTERFACE_NAME_LEN
];
306 trace( "interface table: %u entries\n", buf
->dwNumEntries
);
307 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
309 MIB_IFROW
*row
= &buf
->table
[i
];
310 WideCharToMultiByte( CP_ACP
, 0, row
->wszName
, -1, name
, MAX_INTERFACE_NAME_LEN
, NULL
, NULL
);
311 trace( "%u: '%s' type %u mtu %u speed %u phys",
312 row
->dwIndex
, name
, row
->dwType
, row
->dwMtu
, row
->dwSpeed
);
313 for (j
= 0; j
< row
->dwPhysAddrLen
; j
++)
314 printf( " %02x", row
->bPhysAddr
[j
] );
316 trace( " in: bytes %u upkts %u nupkts %u disc %u err %u unk %u\n",
317 row
->dwInOctets
, row
->dwInUcastPkts
, row
->dwInNUcastPkts
,
318 row
->dwInDiscards
, row
->dwInErrors
, row
->dwInUnknownProtos
);
319 trace( " out: bytes %u upkts %u nupkts %u disc %u err %u\n",
320 row
->dwOutOctets
, row
->dwOutUcastPkts
, row
->dwOutNUcastPkts
,
321 row
->dwOutDiscards
, row
->dwOutErrors
);
324 HeapFree(GetProcessHeap(), 0, buf
);
329 static void testGetIpForwardTable(void)
331 if (gGetIpForwardTable
) {
335 apiReturn
= gGetIpForwardTable(NULL
, NULL
, FALSE
);
336 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
337 skip("GetIpForwardTable is not supported\n");
340 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
341 "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
343 apiReturn
= gGetIpForwardTable(NULL
, &dwSize
, FALSE
);
344 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
345 "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
347 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
348 PMIB_IPFORWARDTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
350 apiReturn
= gGetIpForwardTable(buf
, &dwSize
, FALSE
);
351 ok(apiReturn
== NO_ERROR
,
352 "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
355 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
359 trace( "IP forward table: %u entries\n", buf
->dwNumEntries
);
360 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
363 sprintf( buffer
, "dest %s", ntoa( buf
->table
[i
].dwForwardDest
));
364 sprintf( buffer
+ strlen(buffer
), " mask %s", ntoa( buf
->table
[i
].dwForwardMask
));
365 trace( "%u: %s gw %s if %u type %u\n", i
, buffer
,
366 ntoa( buf
->table
[i
].dwForwardNextHop
),
367 buf
->table
[i
].dwForwardIfIndex
, buf
->table
[i
].dwForwardType
);
370 HeapFree(GetProcessHeap(), 0, buf
);
375 static void testGetIpNetTable(void)
377 if (gGetIpNetTable
) {
381 apiReturn
= gGetIpNetTable(NULL
, NULL
, FALSE
);
382 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
383 skip("GetIpNetTable is not supported\n");
386 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
387 "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
389 apiReturn
= gGetIpNetTable(NULL
, &dwSize
, FALSE
);
390 ok(apiReturn
== ERROR_NO_DATA
|| apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
391 "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n",
393 if (apiReturn
== ERROR_NO_DATA
)
394 ; /* empty ARP table's okay */
395 else if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
396 PMIB_IPNETTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
398 apiReturn
= gGetIpNetTable(buf
, &dwSize
, FALSE
);
399 ok(apiReturn
== NO_ERROR
||
400 apiReturn
== ERROR_NO_DATA
, /* empty ARP table's okay */
401 "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
404 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
408 trace( "IP net table: %u entries\n", buf
->dwNumEntries
);
409 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
411 trace( "%u: idx %u type %u addr %s phys",
412 i
, buf
->table
[i
].dwIndex
, buf
->table
[i
].dwType
, ntoa( buf
->table
[i
].dwAddr
));
413 for (j
= 0; j
< buf
->table
[i
].dwPhysAddrLen
; j
++)
414 printf( " %02x", buf
->table
[i
].bPhysAddr
[j
] );
418 HeapFree(GetProcessHeap(), 0, buf
);
423 static void testGetIcmpStatistics(void)
425 if (gGetIcmpStatistics
) {
429 /* Crashes on Vista */
431 apiReturn
= gGetIcmpStatistics(NULL
);
432 if (apiReturn
== ERROR_NOT_SUPPORTED
)
434 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
435 "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
439 apiReturn
= gGetIcmpStatistics(&stats
);
440 if (apiReturn
== ERROR_NOT_SUPPORTED
)
442 skip("GetIcmpStatistics is not supported\n");
445 ok(apiReturn
== NO_ERROR
,
446 "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
447 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
449 trace( "ICMP stats: %8s %8s\n", "in", "out" );
450 trace( " dwMsgs: %8u %8u\n", stats
.stats
.icmpInStats
.dwMsgs
, stats
.stats
.icmpOutStats
.dwMsgs
);
451 trace( " dwErrors: %8u %8u\n", stats
.stats
.icmpInStats
.dwErrors
, stats
.stats
.icmpOutStats
.dwErrors
);
452 trace( " dwDestUnreachs: %8u %8u\n", stats
.stats
.icmpInStats
.dwDestUnreachs
, stats
.stats
.icmpOutStats
.dwDestUnreachs
);
453 trace( " dwTimeExcds: %8u %8u\n", stats
.stats
.icmpInStats
.dwTimeExcds
, stats
.stats
.icmpOutStats
.dwTimeExcds
);
454 trace( " dwParmProbs: %8u %8u\n", stats
.stats
.icmpInStats
.dwParmProbs
, stats
.stats
.icmpOutStats
.dwParmProbs
);
455 trace( " dwSrcQuenchs: %8u %8u\n", stats
.stats
.icmpInStats
.dwSrcQuenchs
, stats
.stats
.icmpOutStats
.dwSrcQuenchs
);
456 trace( " dwRedirects: %8u %8u\n", stats
.stats
.icmpInStats
.dwRedirects
, stats
.stats
.icmpOutStats
.dwRedirects
);
457 trace( " dwEchos: %8u %8u\n", stats
.stats
.icmpInStats
.dwEchos
, stats
.stats
.icmpOutStats
.dwEchos
);
458 trace( " dwEchoReps: %8u %8u\n", stats
.stats
.icmpInStats
.dwEchoReps
, stats
.stats
.icmpOutStats
.dwEchoReps
);
459 trace( " dwTimestamps: %8u %8u\n", stats
.stats
.icmpInStats
.dwTimestamps
, stats
.stats
.icmpOutStats
.dwTimestamps
);
460 trace( " dwTimestampReps: %8u %8u\n", stats
.stats
.icmpInStats
.dwTimestampReps
, stats
.stats
.icmpOutStats
.dwTimestampReps
);
461 trace( " dwAddrMasks: %8u %8u\n", stats
.stats
.icmpInStats
.dwAddrMasks
, stats
.stats
.icmpOutStats
.dwAddrMasks
);
462 trace( " dwAddrMaskReps: %8u %8u\n", stats
.stats
.icmpInStats
.dwAddrMaskReps
, stats
.stats
.icmpOutStats
.dwAddrMaskReps
);
467 static void testGetIpStatistics(void)
469 if (gGetIpStatistics
) {
473 apiReturn
= gGetIpStatistics(NULL
);
474 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
475 skip("GetIpStatistics is not supported\n");
478 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
479 "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
481 apiReturn
= gGetIpStatistics(&stats
);
482 ok(apiReturn
== NO_ERROR
,
483 "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
484 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
486 trace( "IP stats:\n" );
487 trace( " dwForwarding: %u\n", stats
.dwForwarding
);
488 trace( " dwDefaultTTL: %u\n", stats
.dwDefaultTTL
);
489 trace( " dwInReceives: %u\n", stats
.dwInReceives
);
490 trace( " dwInHdrErrors: %u\n", stats
.dwInHdrErrors
);
491 trace( " dwInAddrErrors: %u\n", stats
.dwInAddrErrors
);
492 trace( " dwForwDatagrams: %u\n", stats
.dwForwDatagrams
);
493 trace( " dwInUnknownProtos: %u\n", stats
.dwInUnknownProtos
);
494 trace( " dwInDiscards: %u\n", stats
.dwInDiscards
);
495 trace( " dwInDelivers: %u\n", stats
.dwInDelivers
);
496 trace( " dwOutRequests: %u\n", stats
.dwOutRequests
);
497 trace( " dwRoutingDiscards: %u\n", stats
.dwRoutingDiscards
);
498 trace( " dwOutDiscards: %u\n", stats
.dwOutDiscards
);
499 trace( " dwOutNoRoutes: %u\n", stats
.dwOutNoRoutes
);
500 trace( " dwReasmTimeout: %u\n", stats
.dwReasmTimeout
);
501 trace( " dwReasmReqds: %u\n", stats
.dwReasmReqds
);
502 trace( " dwReasmOks: %u\n", stats
.dwReasmOks
);
503 trace( " dwReasmFails: %u\n", stats
.dwReasmFails
);
504 trace( " dwFragOks: %u\n", stats
.dwFragOks
);
505 trace( " dwFragFails: %u\n", stats
.dwFragFails
);
506 trace( " dwFragCreates: %u\n", stats
.dwFragCreates
);
507 trace( " dwNumIf: %u\n", stats
.dwNumIf
);
508 trace( " dwNumAddr: %u\n", stats
.dwNumAddr
);
509 trace( " dwNumRoutes: %u\n", stats
.dwNumRoutes
);
514 static void testGetTcpStatistics(void)
516 if (gGetTcpStatistics
) {
520 apiReturn
= gGetTcpStatistics(NULL
);
521 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
522 skip("GetTcpStatistics is not supported\n");
525 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
526 "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
528 apiReturn
= gGetTcpStatistics(&stats
);
529 ok(apiReturn
== NO_ERROR
,
530 "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
531 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
533 trace( "TCP stats:\n" );
534 trace( " dwRtoAlgorithm: %u\n", stats
.dwRtoAlgorithm
);
535 trace( " dwRtoMin: %u\n", stats
.dwRtoMin
);
536 trace( " dwRtoMax: %u\n", stats
.dwRtoMax
);
537 trace( " dwMaxConn: %u\n", stats
.dwMaxConn
);
538 trace( " dwActiveOpens: %u\n", stats
.dwActiveOpens
);
539 trace( " dwPassiveOpens: %u\n", stats
.dwPassiveOpens
);
540 trace( " dwAttemptFails: %u\n", stats
.dwAttemptFails
);
541 trace( " dwEstabResets: %u\n", stats
.dwEstabResets
);
542 trace( " dwCurrEstab: %u\n", stats
.dwCurrEstab
);
543 trace( " dwInSegs: %u\n", stats
.dwInSegs
);
544 trace( " dwOutSegs: %u\n", stats
.dwOutSegs
);
545 trace( " dwRetransSegs: %u\n", stats
.dwRetransSegs
);
546 trace( " dwInErrs: %u\n", stats
.dwInErrs
);
547 trace( " dwOutRsts: %u\n", stats
.dwOutRsts
);
548 trace( " dwNumConns: %u\n", stats
.dwNumConns
);
553 static void testGetUdpStatistics(void)
555 if (gGetUdpStatistics
) {
559 apiReturn
= gGetUdpStatistics(NULL
);
560 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
561 skip("GetUdpStatistics is not supported\n");
564 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
565 "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
567 apiReturn
= gGetUdpStatistics(&stats
);
568 ok(apiReturn
== NO_ERROR
,
569 "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn
);
570 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
572 trace( "UDP stats:\n" );
573 trace( " dwInDatagrams: %u\n", stats
.dwInDatagrams
);
574 trace( " dwNoPorts: %u\n", stats
.dwNoPorts
);
575 trace( " dwInErrors: %u\n", stats
.dwInErrors
);
576 trace( " dwOutDatagrams: %u\n", stats
.dwOutDatagrams
);
577 trace( " dwNumAddrs: %u\n", stats
.dwNumAddrs
);
582 static void testGetTcpTable(void)
588 apiReturn
= gGetTcpTable(NULL
, &dwSize
, FALSE
);
589 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
590 skip("GetTcpTable is not supported\n");
593 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
||
594 broken(apiReturn
== ERROR_NO_DATA
), /* win95 */
595 "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
597 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
598 PMIB_TCPTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
600 apiReturn
= gGetTcpTable(buf
, &dwSize
, FALSE
);
601 ok(apiReturn
== NO_ERROR
,
602 "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
605 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
608 trace( "TCP table: %u entries\n", buf
->dwNumEntries
);
609 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
612 sprintf( buffer
, "local %s:%u",
613 ntoa(buf
->table
[i
].dwLocalAddr
), ntohs(buf
->table
[i
].dwLocalPort
) );
614 trace( "%u: %s remote %s:%u state %u\n",
615 i
, buffer
, ntoa( buf
->table
[i
].dwRemoteAddr
),
616 ntohs(buf
->table
[i
].dwRemotePort
), buf
->table
[i
].dwState
);
619 HeapFree(GetProcessHeap(), 0, buf
);
624 static void testGetUdpTable(void)
630 apiReturn
= gGetUdpTable(NULL
, &dwSize
, FALSE
);
631 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
632 skip("GetUdpTable is not supported\n");
635 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
636 "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
638 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
639 PMIB_UDPTABLE buf
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
641 apiReturn
= gGetUdpTable(buf
, &dwSize
, FALSE
);
642 ok(apiReturn
== NO_ERROR
,
643 "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
646 if (apiReturn
== NO_ERROR
&& winetest_debug
> 1)
649 trace( "UDP table: %u entries\n", buf
->dwNumEntries
);
650 for (i
= 0; i
< buf
->dwNumEntries
; i
++)
651 trace( "%u: %s:%u\n",
652 i
, ntoa( buf
->table
[i
].dwLocalAddr
), ntohs(buf
->table
[i
].dwLocalPort
) );
654 HeapFree(GetProcessHeap(), 0, buf
);
660 still-to-be-tested NT4-onward functions:
674 static void testWinNT4Functions(void)
676 testGetNumberOfInterfaces();
677 testGetIpAddrTable();
679 testGetIpForwardTable();
681 testGetIcmpStatistics();
682 testGetIpStatistics();
683 testGetTcpStatistics();
684 testGetUdpStatistics();
689 static void testGetInterfaceInfo(void)
691 if (gGetInterfaceInfo
) {
695 apiReturn
= gGetInterfaceInfo(NULL
, NULL
);
696 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
697 skip("GetInterfaceInfo is not supported\n");
700 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
701 "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
703 apiReturn
= gGetInterfaceInfo(NULL
, &len
);
704 ok(apiReturn
== ERROR_INSUFFICIENT_BUFFER
,
705 "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
707 if (apiReturn
== ERROR_INSUFFICIENT_BUFFER
) {
708 PIP_INTERFACE_INFO buf
= HeapAlloc(GetProcessHeap(), 0, len
);
710 apiReturn
= gGetInterfaceInfo(buf
, &len
);
711 ok(apiReturn
== NO_ERROR
,
712 "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
714 HeapFree(GetProcessHeap(), 0, buf
);
719 static void testGetAdaptersInfo(void)
721 if (gGetAdaptersInfo
) {
725 apiReturn
= gGetAdaptersInfo(NULL
, NULL
);
726 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
727 skip("GetAdaptersInfo is not supported\n");
730 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
731 "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
733 apiReturn
= gGetAdaptersInfo(NULL
, &len
);
734 ok(apiReturn
== ERROR_NO_DATA
|| apiReturn
== ERROR_BUFFER_OVERFLOW
,
735 "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n",
737 if (apiReturn
== ERROR_NO_DATA
)
738 ; /* no adapter's, that's okay */
739 else if (apiReturn
== ERROR_BUFFER_OVERFLOW
) {
740 PIP_ADAPTER_INFO buf
= HeapAlloc(GetProcessHeap(), 0, len
);
742 apiReturn
= gGetAdaptersInfo(buf
, &len
);
743 ok(apiReturn
== NO_ERROR
,
744 "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
746 HeapFree(GetProcessHeap(), 0, buf
);
751 static void testGetNetworkParams(void)
753 if (gGetNetworkParams
) {
757 apiReturn
= gGetNetworkParams(NULL
, NULL
);
758 if (apiReturn
== ERROR_NOT_SUPPORTED
) {
759 skip("GetNetworkParams is not supported\n");
762 ok(apiReturn
== ERROR_INVALID_PARAMETER
,
763 "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n",
765 apiReturn
= gGetNetworkParams(NULL
, &len
);
766 ok(apiReturn
== ERROR_BUFFER_OVERFLOW
,
767 "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n",
769 if (apiReturn
== ERROR_BUFFER_OVERFLOW
) {
770 PFIXED_INFO buf
= HeapAlloc(GetProcessHeap(), 0, len
);
772 apiReturn
= gGetNetworkParams(buf
, &len
);
773 ok(apiReturn
== NO_ERROR
,
774 "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n",
776 HeapFree(GetProcessHeap(), 0, buf
);
782 still-to-be-tested 98-onward functions:
788 static DWORD CALLBACK
testWin98Functions(void *p
)
790 testGetInterfaceInfo();
791 testGetAdaptersInfo();
792 testGetNetworkParams();
796 static void testGetPerAdapterInfo(void)
801 if (!gGetPerAdapterInfo
) return;
802 ret
= gGetPerAdapterInfo(1, NULL
, NULL
);
803 if (ret
== ERROR_NOT_SUPPORTED
) {
804 skip("GetPerAdapterInfo is not supported\n");
807 ok( ret
== ERROR_INVALID_PARAMETER
, "got %u instead of ERROR_INVALID_PARAMETER\n", ret
);
809 ret
= gGetPerAdapterInfo(1, NULL
, &needed
);
810 if (ret
== ERROR_NO_DATA
) return; /* no such adapter */
811 ok( ret
== ERROR_BUFFER_OVERFLOW
, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret
);
812 ok( needed
!= 0xdeadbeef, "needed not set\n" );
813 buffer
= HeapAlloc( GetProcessHeap(), 0, needed
);
814 ret
= gGetPerAdapterInfo(1, buffer
, &needed
);
815 ok( ret
== NO_ERROR
, "got %u instead of NO_ERROR\n", ret
);
816 HeapFree( GetProcessHeap(), 0, buffer
);
819 static void testNotifyAddrChange(void)
822 OVERLAPPED overlapped
;
826 if (!gNotifyAddrChange
)
828 win_skip("NotifyAddrChange not present\n");
831 if (!gCancelIPChangeNotify
)
833 win_skip("CancelIPChangeNotify not present\n");
838 ZeroMemory(&overlapped
, sizeof(overlapped
));
839 ret
= gNotifyAddrChange(&handle
, &overlapped
);
840 if (ret
== ERROR_NOT_SUPPORTED
)
842 win_skip("NotifyAddrChange is not supported\n");
845 ok(ret
== ERROR_IO_PENDING
, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret
);
846 ret
= GetLastError();
847 todo_wine
ok(ret
== ERROR_IO_PENDING
, "GetLastError returned %d, expected ERROR_IO_PENDING\n", ret
);
848 success
= gCancelIPChangeNotify(&overlapped
);
849 todo_wine
ok(success
== TRUE
, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
851 ZeroMemory(&overlapped
, sizeof(overlapped
));
852 success
= gCancelIPChangeNotify(&overlapped
);
853 ok(success
== FALSE
, "CancelIPChangeNotify returned TRUE, expected FALSE\n");
856 ZeroMemory(&overlapped
, sizeof(overlapped
));
857 overlapped
.hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
858 ret
= gNotifyAddrChange(&handle
, &overlapped
);
859 ok(ret
== ERROR_IO_PENDING
, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret
);
860 todo_wine
ok(handle
!= INVALID_HANDLE_VALUE
, "NotifyAddrChange returned invalid file handle\n");
861 success
= GetOverlappedResult(handle
, &overlapped
, &bytes
, FALSE
);
862 ok(success
== FALSE
, "GetOverlappedResult returned TRUE, expected FALSE\n");
863 ret
= GetLastError();
864 ok(ret
== ERROR_IO_INCOMPLETE
, "GetLastError returned %d, expected ERROR_IO_INCOMPLETE\n", ret
);
865 success
= gCancelIPChangeNotify(&overlapped
);
866 todo_wine
ok(success
== TRUE
, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
868 if (winetest_interactive
)
871 ZeroMemory(&overlapped
, sizeof(overlapped
));
872 overlapped
.hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
873 trace("Testing asynchronous ipv4 address change notification. Please "
874 "change the ipv4 address of one of your network interfaces\n");
875 ret
= gNotifyAddrChange(&handle
, &overlapped
);
876 ok(ret
== ERROR_IO_PENDING
, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret
);
877 success
= GetOverlappedResult(handle
, &overlapped
, &bytes
, TRUE
);
878 ok(success
== TRUE
, "GetOverlappedResult returned FALSE, expected TRUE\n");
881 /* test synchronous functionality */
882 if (winetest_interactive
)
884 trace("Testing synchronous ipv4 address change notification. Please "
885 "change the ipv4 address of one of your network interfaces\n");
886 ret
= gNotifyAddrChange(NULL
, NULL
);
887 todo_wine
ok(ret
== NO_ERROR
, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret
);
892 still-to-be-tested 2K-onward functions:
900 NotifyRouteChange + CancelIPChangeNotify
904 static void testWin2KFunctions(void)
906 testGetPerAdapterInfo();
907 testNotifyAddrChange();
910 static void test_GetAdaptersAddresses(void)
913 IP_ADAPTER_ADDRESSES
*aa
, *ptr
;
914 IP_ADAPTER_UNICAST_ADDRESS
*ua
;
916 if (!gGetAdaptersAddresses
)
918 win_skip("GetAdaptersAddresses not present\n");
922 ret
= gGetAdaptersAddresses(AF_UNSPEC
, 0, NULL
, NULL
, NULL
);
923 ok(ret
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER got %u\n", ret
);
925 /* size should be ignored and overwritten if buffer is NULL */
927 ret
= gGetAdaptersAddresses(AF_UNSPEC
, 0, NULL
, NULL
, &size
);
928 ok(ret
== ERROR_BUFFER_OVERFLOW
, "expected ERROR_BUFFER_OVERFLOW, got %u\n", ret
);
929 if (ret
!= ERROR_BUFFER_OVERFLOW
) return;
931 ptr
= HeapAlloc(GetProcessHeap(), 0, size
);
932 ret
= gGetAdaptersAddresses(AF_UNSPEC
, 0, NULL
, ptr
, &size
);
933 ok(!ret
, "expected ERROR_SUCCESS got %u\n", ret
);
935 for (aa
= ptr
; !ret
&& aa
; aa
= aa
->Next
)
937 ok(aa
->DnsSuffix
!= NULL
, "DnsSuffix is not a valid pointer\n");
938 ok(aa
->Description
!= NULL
, "Description is not a valid pointer\n");
939 ok(aa
->FriendlyName
!= NULL
, "FriendlyName is not a valid pointer\n");
941 if (winetest_debug
<= 1)
944 trace("Length: %u\n", S(U(*aa
)).Length
);
945 trace("IfIndex: %u\n", S(U(*aa
)).IfIndex
);
946 trace("Next: %p\n", aa
->Next
);
947 trace("AdapterName: %s\n", aa
->AdapterName
);
948 trace("FirstUnicastAddress: %p\n", aa
->FirstUnicastAddress
);
949 ua
= aa
->FirstUnicastAddress
;
952 trace("\tLength: %u\n", S(U(*ua
)).Length
);
953 trace("\tFlags: 0x%08x\n", S(U(*ua
)).Flags
);
954 trace("\tNext: %p\n", ua
->Next
);
955 trace("\tAddress.lpSockaddr: %p\n", ua
->Address
.lpSockaddr
);
956 trace("\tAddress.iSockaddrLength: %d\n", ua
->Address
.iSockaddrLength
);
957 trace("\tPrefixOrigin: %u\n", ua
->PrefixOrigin
);
958 trace("\tSuffixOrigin: %u\n", ua
->SuffixOrigin
);
959 trace("\tDadState: %u\n", ua
->DadState
);
960 trace("\tValidLifetime: 0x%08x\n", ua
->ValidLifetime
);
961 trace("\tPreferredLifetime: 0x%08x\n", ua
->PreferredLifetime
);
962 trace("\tLeaseLifetime: 0x%08x\n", ua
->LeaseLifetime
);
966 trace("FirstAnycastAddress: %p\n", aa
->FirstAnycastAddress
);
967 trace("FirstMulticastAddress: %p\n", aa
->FirstMulticastAddress
);
968 trace("FirstDnsServerAddress: %p\n", aa
->FirstDnsServerAddress
);
969 trace("DnsSuffix: %p\n", aa
->DnsSuffix
);
970 trace("Description: %p\n", aa
->Description
);
971 trace("FriendlyName: %p\n", aa
->FriendlyName
);
972 trace("PhysicalAddress: %02x\n", aa
->PhysicalAddress
[0]);
973 trace("PhysicalAddressLength: %u\n", aa
->PhysicalAddressLength
);
974 trace("Flags: 0x%08x\n", aa
->Flags
);
975 trace("Mtu: %u\n", aa
->Mtu
);
976 trace("IfType: %u\n", aa
->IfType
);
977 trace("OperStatus: %u\n", aa
->OperStatus
);
980 HeapFree(GetProcessHeap(), 0, ptr
);
990 testWin98OnlyFunctions();
991 testWinNT4Functions();
993 /* run testGetXXXX in two threads at once to make sure we don't crash in that case */
994 thread
= CreateThread(NULL
, 0, testWin98Functions
, NULL
, 0, NULL
);
995 testWin98Functions(NULL
);
996 WaitForSingleObject(thread
, INFINITE
);
998 testWin2KFunctions();
999 test_GetAdaptersAddresses();