winhttp: Test secure connections. Fix a crash when no response is returned.
[wine] / dlls / iphlpapi / tests / iphlpapi.c
1 /*
2  * iphlpapi dll test
3  *
4  * Copyright (C) 2003 Juan Lang
5  *
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.
10  *
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.
15  *
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
19  */
20
21 /*
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).
28  *
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.
33  *
34  * The DomainName field of FIXED_INFO isn't NULL-terminated on Win98.
35  */
36
37 #include <stdarg.h>
38 #include "windef.h"
39 #include "winbase.h"
40 #include "iphlpapi.h"
41 #include "iprtrmib.h"
42 #include "wine/test.h"
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 static HMODULE hLibrary = NULL;
47
48 typedef DWORD (WINAPI *GetNumberOfInterfacesFunc)(PDWORD);
49 typedef DWORD (WINAPI *GetIpAddrTableFunc)(PMIB_IPADDRTABLE,PULONG,BOOL);
50 typedef DWORD (WINAPI *GetIfEntryFunc)(PMIB_IFROW);
51 typedef DWORD (WINAPI *GetFriendlyIfIndexFunc)(DWORD);
52 typedef DWORD (WINAPI *GetIfTableFunc)(PMIB_IFTABLE,PULONG,BOOL);
53 typedef DWORD (WINAPI *GetIpForwardTableFunc)(PMIB_IPFORWARDTABLE,PULONG,BOOL);
54 typedef DWORD (WINAPI *GetIpNetTableFunc)(PMIB_IPNETTABLE,PULONG,BOOL);
55 typedef DWORD (WINAPI *GetInterfaceInfoFunc)(PIP_INTERFACE_INFO,PULONG);
56 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO,PULONG);
57 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO,PULONG);
58 typedef DWORD (WINAPI *GetIcmpStatisticsFunc)(PMIB_ICMP);
59 typedef DWORD (WINAPI *GetIpStatisticsFunc)(PMIB_IPSTATS);
60 typedef DWORD (WINAPI *GetTcpStatisticsFunc)(PMIB_TCPSTATS);
61 typedef DWORD (WINAPI *GetUdpStatisticsFunc)(PMIB_UDPSTATS);
62 typedef DWORD (WINAPI *GetTcpTableFunc)(PMIB_TCPTABLE,PDWORD,BOOL);
63 typedef DWORD (WINAPI *GetUdpTableFunc)(PMIB_UDPTABLE,PDWORD,BOOL);
64 typedef DWORD (WINAPI *GetPerAdapterInfoFunc)(ULONG,PIP_PER_ADAPTER_INFO,PULONG);
65
66 static GetNumberOfInterfacesFunc gGetNumberOfInterfaces = NULL;
67 static GetIpAddrTableFunc gGetIpAddrTable = NULL;
68 static GetIfEntryFunc gGetIfEntry = NULL;
69 static GetFriendlyIfIndexFunc gGetFriendlyIfIndex = NULL;
70 static GetIfTableFunc gGetIfTable = NULL;
71 static GetIpForwardTableFunc gGetIpForwardTable = NULL;
72 static GetIpNetTableFunc gGetIpNetTable = NULL;
73 static GetInterfaceInfoFunc gGetInterfaceInfo = NULL;
74 static GetAdaptersInfoFunc gGetAdaptersInfo = NULL;
75 static GetNetworkParamsFunc gGetNetworkParams = NULL;
76 static GetIcmpStatisticsFunc gGetIcmpStatistics = NULL;
77 static GetIpStatisticsFunc gGetIpStatistics = NULL;
78 static GetTcpStatisticsFunc gGetTcpStatistics = NULL;
79 static GetUdpStatisticsFunc gGetUdpStatistics = NULL;
80 static GetTcpTableFunc gGetTcpTable = NULL;
81 static GetUdpTableFunc gGetUdpTable = NULL;
82 static GetPerAdapterInfoFunc gGetPerAdapterInfo = NULL;
83
84 static void loadIPHlpApi(void)
85 {
86   hLibrary = LoadLibraryA("iphlpapi.dll");
87   if (hLibrary) {
88     gGetNumberOfInterfaces = (GetNumberOfInterfacesFunc)GetProcAddress(
89      hLibrary, "GetNumberOfInterfaces");
90     gGetIpAddrTable = (GetIpAddrTableFunc)GetProcAddress(
91      hLibrary, "GetIpAddrTable");
92     gGetIfEntry = (GetIfEntryFunc)GetProcAddress(
93      hLibrary, "GetIfEntry");
94     gGetFriendlyIfIndex = (GetFriendlyIfIndexFunc)GetProcAddress(
95      hLibrary, "GetFriendlyIfIndex");
96     gGetIfTable = (GetIfTableFunc)GetProcAddress(
97      hLibrary, "GetIfTable");
98     gGetIpForwardTable = (GetIpForwardTableFunc)GetProcAddress(
99      hLibrary, "GetIpForwardTable");
100     gGetIpNetTable = (GetIpNetTableFunc)GetProcAddress(
101      hLibrary, "GetIpNetTable");
102     gGetInterfaceInfo = (GetInterfaceInfoFunc)GetProcAddress(
103      hLibrary, "GetInterfaceInfo");
104     gGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(
105      hLibrary, "GetAdaptersInfo");
106     gGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(
107      hLibrary, "GetNetworkParams");
108     gGetIcmpStatistics = (GetIcmpStatisticsFunc)GetProcAddress(
109      hLibrary, "GetIcmpStatistics");
110     gGetIpStatistics = (GetIpStatisticsFunc)GetProcAddress(
111      hLibrary, "GetIpStatistics");
112     gGetTcpStatistics = (GetTcpStatisticsFunc)GetProcAddress(
113      hLibrary, "GetTcpStatistics");
114     gGetUdpStatistics = (GetUdpStatisticsFunc)GetProcAddress(
115      hLibrary, "GetUdpStatistics");
116     gGetTcpTable = (GetTcpTableFunc)GetProcAddress(
117      hLibrary, "GetTcpTable");
118     gGetUdpTable = (GetUdpTableFunc)GetProcAddress(
119      hLibrary, "GetUdpTable");
120     gGetPerAdapterInfo = (GetPerAdapterInfoFunc)GetProcAddress(hLibrary, "GetPerAdapterInfo");
121   }
122 }
123
124 static void freeIPHlpApi(void)
125 {
126   if (hLibrary) {
127     gGetNumberOfInterfaces = NULL;
128     gGetIpAddrTable = NULL;
129     gGetIfEntry = NULL;
130     gGetFriendlyIfIndex = NULL;
131     gGetIfTable = NULL;
132     gGetIpForwardTable = NULL;
133     gGetIpNetTable = NULL;
134     gGetInterfaceInfo = NULL;
135     gGetAdaptersInfo = NULL;
136     gGetNetworkParams = NULL;
137     gGetIcmpStatistics = NULL;
138     gGetIpStatistics = NULL;
139     gGetTcpStatistics = NULL;
140     gGetUdpStatistics = NULL;
141     gGetTcpTable = NULL;
142     gGetUdpTable = NULL;
143     FreeLibrary(hLibrary);
144     hLibrary = NULL;
145   }
146 }
147
148 /*
149 still-to-be-tested 98-only functions:
150 GetUniDirectionalAdapterInfo
151 */
152 static void testWin98OnlyFunctions(void)
153 {
154 }
155
156 static void testGetNumberOfInterfaces(void)
157 {
158   if (gGetNumberOfInterfaces) {
159     DWORD apiReturn, numInterfaces;
160
161     /* Crashes on Vista */
162     if (0) {
163       apiReturn = gGetNumberOfInterfaces(NULL), numInterfaces;
164       if (apiReturn == ERROR_NOT_SUPPORTED)
165         return;
166       ok(apiReturn == ERROR_INVALID_PARAMETER,
167        "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
168        apiReturn);
169     }
170
171     apiReturn = gGetNumberOfInterfaces(&numInterfaces);
172     if (apiReturn == ERROR_NOT_SUPPORTED) {
173       skip("GetNumberOfInterfaces is not supported\n");
174       return;
175     }
176     ok(apiReturn == NO_ERROR,
177      "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn);
178   }
179 }
180
181 static void testGetIfEntry(DWORD index)
182 {
183   if (gGetIfEntry) {
184     DWORD apiReturn;
185     MIB_IFROW row;
186
187     memset(&row, 0, sizeof(row));
188     apiReturn = gGetIfEntry(NULL);
189     if (apiReturn == ERROR_NOT_SUPPORTED) {
190       skip("GetIfEntry is not supported\n");
191       return;
192     }
193     ok(apiReturn == ERROR_INVALID_PARAMETER,
194      "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
195      apiReturn);
196     row.dwIndex = -1; /* hope that's always bogus! */
197     apiReturn = gGetIfEntry(&row);
198     ok(apiReturn == ERROR_INVALID_DATA ||
199      apiReturn == ERROR_FILE_NOT_FOUND /* Vista */,
200      "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n",
201      apiReturn);
202     row.dwIndex = index;
203     apiReturn = gGetIfEntry(&row);
204     ok(apiReturn == NO_ERROR, 
205      "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn);
206   }
207 }
208
209 static void testGetIpAddrTable(void)
210 {
211   if (gGetIpAddrTable) {
212     DWORD apiReturn;
213     ULONG dwSize = 0;
214
215     apiReturn = gGetIpAddrTable(NULL, NULL, FALSE);
216     if (apiReturn == ERROR_NOT_SUPPORTED) {
217       skip("GetIpAddrTable is not supported\n");
218       return;
219     }
220     ok(apiReturn == ERROR_INVALID_PARAMETER,
221      "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
222      apiReturn);
223     apiReturn = gGetIpAddrTable(NULL, &dwSize, FALSE);
224     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
225      "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
226      apiReturn);
227     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
228       PMIB_IPADDRTABLE buf = (PMIB_IPADDRTABLE)malloc(dwSize);
229
230       apiReturn = gGetIpAddrTable(buf, &dwSize, FALSE);
231       ok(apiReturn == NO_ERROR,
232        "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
233        apiReturn);
234       if (apiReturn == NO_ERROR && buf->dwNumEntries)
235         testGetIfEntry(buf->table[0].dwIndex);
236       free(buf);
237     }
238   }
239 }
240
241 static void testGetIfTable(void)
242 {
243   if (gGetIfTable) {
244     DWORD apiReturn;
245     ULONG dwSize = 0;
246
247     apiReturn = gGetIfTable(NULL, NULL, FALSE);
248     if (apiReturn == ERROR_NOT_SUPPORTED) {
249       skip("GetIfTable is not supported\n");
250       return;
251     }
252     ok(apiReturn == ERROR_INVALID_PARAMETER,
253      "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
254      apiReturn);
255     apiReturn = gGetIfTable(NULL, &dwSize, FALSE);
256     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
257      "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
258      apiReturn);
259     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
260       PMIB_IFTABLE buf = (PMIB_IFTABLE)malloc(dwSize);
261
262       apiReturn = gGetIfTable(buf, &dwSize, FALSE);
263       ok(apiReturn == NO_ERROR,
264        "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n",
265        apiReturn);
266       free(buf);
267     }
268   }
269 }
270
271 static void testGetIpForwardTable(void)
272 {
273   if (gGetIpForwardTable) {
274     DWORD apiReturn;
275     ULONG dwSize = 0;
276
277     apiReturn = gGetIpForwardTable(NULL, NULL, FALSE);
278     if (apiReturn == ERROR_NOT_SUPPORTED) {
279       skip("GetIpForwardTable is not supported\n");
280       return;
281     }
282     ok(apiReturn == ERROR_INVALID_PARAMETER,
283      "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
284      apiReturn);
285     apiReturn = gGetIpForwardTable(NULL, &dwSize, FALSE);
286     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
287      "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
288      apiReturn);
289     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
290       PMIB_IPFORWARDTABLE buf = (PMIB_IPFORWARDTABLE)malloc(dwSize);
291
292       apiReturn = gGetIpForwardTable(buf, &dwSize, FALSE);
293       ok(apiReturn == NO_ERROR,
294        "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
295        apiReturn);
296       free(buf);
297     }
298   }
299 }
300
301 static void testGetIpNetTable(void)
302 {
303   if (gGetIpNetTable) {
304     DWORD apiReturn;
305     ULONG dwSize = 0;
306
307     apiReturn = gGetIpNetTable(NULL, NULL, FALSE);
308     if (apiReturn == ERROR_NOT_SUPPORTED) {
309       skip("GetIpNetTable is not supported\n");
310       return;
311     }
312     ok(apiReturn == ERROR_INVALID_PARAMETER,
313      "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
314      apiReturn);
315     apiReturn = gGetIpNetTable(NULL, &dwSize, FALSE);
316     ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_INSUFFICIENT_BUFFER,
317      "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n",
318      apiReturn);
319     if (apiReturn == ERROR_NO_DATA)
320       ; /* empty ARP table's okay */
321     else if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
322       PMIB_IPNETTABLE buf = (PMIB_IPNETTABLE)malloc(dwSize);
323
324       apiReturn = gGetIpNetTable(buf, &dwSize, FALSE);
325       ok(apiReturn == NO_ERROR,
326        "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
327        apiReturn);
328       free(buf);
329     }
330   }
331 }
332
333 static void testGetIcmpStatistics(void)
334 {
335   if (gGetIcmpStatistics) {
336     DWORD apiReturn;
337     MIB_ICMP stats;
338
339     /* Crashes on Vista */
340     if (0) {
341       apiReturn = gGetIcmpStatistics(NULL);
342       if (apiReturn == ERROR_NOT_SUPPORTED)
343         return;
344       ok(apiReturn == ERROR_INVALID_PARAMETER,
345        "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
346        apiReturn);
347     }
348
349     apiReturn = gGetIcmpStatistics(&stats);
350     if (apiReturn == ERROR_NOT_SUPPORTED)
351     {
352       skip("GetIcmpStatistics is not supported\n");
353       return;
354     }
355     ok(apiReturn == NO_ERROR,
356      "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn);
357   }
358 }
359
360 static void testGetIpStatistics(void)
361 {
362   if (gGetIpStatistics) {
363     DWORD apiReturn;
364     MIB_IPSTATS stats;
365
366     apiReturn = gGetIpStatistics(NULL);
367     if (apiReturn == ERROR_NOT_SUPPORTED) {
368       skip("GetIpStatistics is not supported\n");
369       return;
370     }
371     ok(apiReturn == ERROR_INVALID_PARAMETER,
372      "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
373      apiReturn);
374     apiReturn = gGetIpStatistics(&stats);
375     ok(apiReturn == NO_ERROR,
376       "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn);
377   }
378 }
379
380 static void testGetTcpStatistics(void)
381 {
382   if (gGetTcpStatistics) {
383     DWORD apiReturn;
384     MIB_TCPSTATS stats;
385
386     apiReturn = gGetTcpStatistics(NULL);
387     if (apiReturn == ERROR_NOT_SUPPORTED) {
388       skip("GetTcpStatistics is not supported\n");
389       return;
390     }
391     ok(apiReturn == ERROR_INVALID_PARAMETER,
392      "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
393      apiReturn);
394     apiReturn = gGetTcpStatistics(&stats);
395     ok(apiReturn == NO_ERROR,
396       "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn);
397   }
398 }
399
400 static void testGetUdpStatistics(void)
401 {
402   if (gGetUdpStatistics) {
403     DWORD apiReturn;
404     MIB_UDPSTATS stats;
405
406     apiReturn = gGetUdpStatistics(NULL);
407     if (apiReturn == ERROR_NOT_SUPPORTED) {
408       skip("GetUdpStatistics is not supported\n");
409       return;
410     }
411     ok(apiReturn == ERROR_INVALID_PARAMETER,
412      "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
413      apiReturn);
414     apiReturn = gGetUdpStatistics(&stats);
415     ok(apiReturn == NO_ERROR,
416      "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn);
417   }
418 }
419
420 static void testGetTcpTable(void)
421 {
422   if (gGetTcpTable) {
423     DWORD apiReturn;
424     ULONG dwSize = 0;
425
426     apiReturn = gGetTcpTable(NULL, NULL, FALSE);
427     if (apiReturn == ERROR_NOT_SUPPORTED) {
428       skip("GetTcpTable is not supported\n");
429       return;
430     }
431     ok(apiReturn == ERROR_INVALID_PARAMETER,
432      "GetTcpTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
433      apiReturn);
434     apiReturn = gGetTcpTable(NULL, &dwSize, FALSE);
435     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
436      "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
437      apiReturn);
438     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
439       PMIB_TCPTABLE buf = (PMIB_TCPTABLE)malloc(dwSize);
440
441       apiReturn = gGetTcpTable(buf, &dwSize, FALSE);
442       ok(apiReturn == NO_ERROR,
443        "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
444        apiReturn);
445       free(buf);
446     }
447   }
448 }
449
450 static void testGetUdpTable(void)
451 {
452   if (gGetUdpTable) {
453     DWORD apiReturn;
454     ULONG dwSize = 0;
455
456     apiReturn = gGetUdpTable(NULL, NULL, FALSE);
457     if (apiReturn == ERROR_NOT_SUPPORTED) {
458       skip("GetUdpTable is not supported\n");
459       return;
460     }
461     ok(apiReturn == ERROR_INVALID_PARAMETER,
462      "GetUdpTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
463      apiReturn);
464     apiReturn = gGetUdpTable(NULL, &dwSize, FALSE);
465     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
466      "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
467      apiReturn);
468     if (apiReturn != ERROR_INSUFFICIENT_BUFFER) {
469       PMIB_UDPTABLE buf = (PMIB_UDPTABLE)malloc(dwSize);
470
471       apiReturn = gGetUdpTable(buf, &dwSize, FALSE);
472       ok(apiReturn == NO_ERROR,
473        "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
474        apiReturn);
475       free(buf);
476     }
477   }
478 }
479
480 /*
481 still-to-be-tested NT4-onward functions:
482 CreateIpForwardEntry
483 DeleteIpForwardEntry
484 CreateIpNetEntry
485 DeleteIpNetEntry
486 GetFriendlyIfIndex
487 GetRTTAndHopCount
488 SetIfEntry
489 SetIpForwardEntry
490 SetIpNetEntry
491 SetIpStatistics
492 SetIpTTL
493 SetTcpEntry
494 */
495 static void testWinNT4Functions(void)
496 {
497   testGetNumberOfInterfaces();
498   testGetIpAddrTable();
499   testGetIfTable();
500   testGetIpForwardTable();
501   testGetIpNetTable();
502   testGetIcmpStatistics();
503   testGetIpStatistics();
504   testGetTcpStatistics();
505   testGetUdpStatistics();
506   testGetTcpTable();
507   testGetUdpTable();
508 }
509
510 static void testGetInterfaceInfo(void)
511 {
512   if (gGetInterfaceInfo) {
513     DWORD apiReturn;
514     ULONG len = 0;
515
516     apiReturn = gGetInterfaceInfo(NULL, NULL);
517     if (apiReturn == ERROR_NOT_SUPPORTED) {
518       skip("GetInterfaceInfo is not supported\n");
519       return;
520     }
521     ok(apiReturn == ERROR_INVALID_PARAMETER,
522      "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
523      apiReturn);
524     apiReturn = gGetInterfaceInfo(NULL, &len);
525     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
526      "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
527      apiReturn);
528     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
529       PIP_INTERFACE_INFO buf = (PIP_INTERFACE_INFO)malloc(len);
530
531       apiReturn = gGetInterfaceInfo(buf, &len);
532       ok(apiReturn == NO_ERROR,
533        "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
534        apiReturn);
535       free(buf);
536     }
537   }
538 }
539
540 static void testGetAdaptersInfo(void)
541 {
542   if (gGetAdaptersInfo) {
543     DWORD apiReturn;
544     ULONG len = 0;
545
546     apiReturn = gGetAdaptersInfo(NULL, NULL);
547     if (apiReturn == ERROR_NOT_SUPPORTED) {
548       skip("GetAdaptersInfo is not supported\n");
549       return;
550     }
551     ok(apiReturn == ERROR_INVALID_PARAMETER,
552      "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
553      apiReturn);
554     apiReturn = gGetAdaptersInfo(NULL, &len);
555     ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_BUFFER_OVERFLOW,
556      "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n",
557      apiReturn);
558     if (apiReturn == ERROR_NO_DATA)
559       ; /* no adapter's, that's okay */
560     else if (apiReturn == ERROR_BUFFER_OVERFLOW) {
561       PIP_ADAPTER_INFO buf = (PIP_ADAPTER_INFO)malloc(len);
562
563       apiReturn = gGetAdaptersInfo(buf, &len);
564       ok(apiReturn == NO_ERROR,
565        "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
566        apiReturn);
567       free(buf);
568     }
569   }
570 }
571
572 static void testGetNetworkParams(void)
573 {
574   if (gGetNetworkParams) {
575     DWORD apiReturn;
576     ULONG len = 0;
577
578     apiReturn = gGetNetworkParams(NULL, NULL);
579     if (apiReturn == ERROR_NOT_SUPPORTED) {
580       skip("GetNetworkParams is not supported\n");
581       return;
582     }
583     ok(apiReturn == ERROR_INVALID_PARAMETER,
584      "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n",
585      apiReturn);
586     apiReturn = gGetNetworkParams(NULL, &len);
587     ok(apiReturn == ERROR_BUFFER_OVERFLOW,
588      "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n",
589      apiReturn);
590     if (apiReturn == ERROR_BUFFER_OVERFLOW) {
591       PFIXED_INFO buf = (PFIXED_INFO)malloc(len);
592
593       apiReturn = gGetNetworkParams(buf, &len);
594       ok(apiReturn == NO_ERROR,
595        "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n",
596        apiReturn);
597       free(buf);
598     }
599   }
600 }
601
602 /*
603 still-to-be-tested 98-onward functions:
604 GetBestInterface
605 GetBestRoute
606 IpReleaseAddress
607 IpRenewAddress
608 */
609 static void testWin98Functions(void)
610 {
611   testGetInterfaceInfo();
612   testGetAdaptersInfo();
613   testGetNetworkParams();
614 }
615
616 static void testGetPerAdapterInfo(void)
617 {
618     DWORD ret, needed;
619     void *buffer;
620
621     if (!gGetPerAdapterInfo) return;
622     ret = gGetPerAdapterInfo(1, NULL, NULL);
623     if (ret == ERROR_NOT_SUPPORTED) {
624       skip("GetPerAdapterInfo is not supported\n");
625       return;
626     }
627     ok( ret == ERROR_INVALID_PARAMETER, "got %u instead of ERROR_INVALID_PARAMETER\n", ret );
628     needed = 0xdeadbeef;
629     ret = gGetPerAdapterInfo(1, NULL, &needed);
630     if (ret == ERROR_NO_DATA) return;  /* no such adapter */
631     ok( ret == ERROR_BUFFER_OVERFLOW, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret );
632     ok( needed != 0xdeadbeef, "needed not set\n" );
633     buffer = HeapAlloc( GetProcessHeap(), 0, needed );
634     ret = gGetPerAdapterInfo(1, buffer, &needed);
635     ok( ret == NO_ERROR, "got %u instead of NO_ERROR\n", ret );
636     HeapFree( GetProcessHeap(), 0, buffer );
637 }
638
639 /*
640 still-to-be-tested 2K-onward functions:
641 AddIPAddress
642 CreateProxyArpEntry
643 DeleteIPAddress
644 DeleteProxyArpEntry
645 EnableRouter
646 FlushIpNetTable
647 GetAdapterIndex
648 NotifyAddrChange
649 NotifyRouteChange
650 SendARP
651 UnenableRouter
652 */
653 static void testWin2KFunctions(void)
654 {
655     testGetPerAdapterInfo();
656 }
657
658 START_TEST(iphlpapi)
659 {
660
661   loadIPHlpApi();
662   if (hLibrary) {
663     testWin98OnlyFunctions();
664     testWinNT4Functions();
665     testWin98Functions();
666     testWin2KFunctions();
667     freeIPHlpApi();
668   }
669 }