_read(): In _O_TEXT mode make Readfile calls in chunks as big as
[wine] / dlls / iphlpapi / iphlpapi_main.c
1 /*
2  * iphlpapi dll implementation
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #ifdef HAVE_NETINET_IN_H
27 # include <netinet/in.h>
28 #endif
29 #ifdef HAVE_ARPA_NAMESER_H
30 # include <arpa/nameser.h>
31 #endif
32 #ifdef HAVE_RESOLV_H
33 # include <resolv.h>
34 #endif
35
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "iphlpapi.h"
40 #include "ifenum.h"
41 #include "ipstats.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
45
46
47 /******************************************************************
48  *    AddIPAddress (IPHLPAPI.@)
49  *
50  *
51  * PARAMS
52  *
53  *  Address [In]
54  *  IpMask [In]
55  *  IfIndex [In]
56  *  NTEContext [In/Out]
57  *  NTEInstance [In/Out]
58  *
59  * RETURNS
60  *
61  *  DWORD
62  *
63  */
64 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
65 {
66   FIXME(":stub\n");
67   /* marking Win2K+ functions not supported */
68   return ERROR_NOT_SUPPORTED;
69 }
70
71
72 /******************************************************************
73  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
74  *
75  *
76  * PARAMS
77  *
78  *  ppIfTable [Out] -- pointer into which the MIB_IFTABLE is
79  *   allocated and returned.
80  *  bOrder [In] -- passed to GetIfTable to order the table
81  *  heap [In] -- heap from which the table is allocated
82  *  flags [In] -- flags to HeapAlloc
83  *
84  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
85  *  GetIfTable returns otherwise
86  *
87  */
88 DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
89  BOOL bOrder, HANDLE heap, DWORD flags)
90 {
91   DWORD ret;
92
93   if (!ppIfTable)
94     ret = ERROR_INVALID_PARAMETER;
95   else {
96     DWORD dwSize = 0;
97
98     ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
99     if (ret == ERROR_INSUFFICIENT_BUFFER) {
100       *ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize);
101       ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
102     }
103   }
104   return ret;
105 }
106
107
108 /******************************************************************
109  *    AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
110  *
111  *
112  * PARAMS
113  *
114  *  ppIpAddrTable [Out]
115  *  bOrder [In] -- passed to GetIpAddrTable to order the table
116  *  heap [In] -- heap from which the table is allocated
117  *  flags [In] -- flags to HeapAlloc
118  *
119  * RETURNS
120  *
121  *  DWORD
122  *
123  */
124 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
125  BOOL bOrder, HANDLE heap, DWORD flags)
126 {
127   DWORD ret;
128
129   if (!ppIpAddrTable)
130     ret = ERROR_INVALID_PARAMETER;
131   else {
132     DWORD dwSize = 0;
133
134     ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
135     if (ret == ERROR_INSUFFICIENT_BUFFER) {
136       *ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize);
137       ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
138     }
139   }
140   return ret;
141 }
142
143
144 /******************************************************************
145  *    AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
146  *
147  *
148  *  ppIpForwardTable [Out] -- pointer into which the MIB_IPFORWARDTABLE is
149  *   allocated and returned.
150  *  bOrder [In] -- passed to GetIfTable to order the table
151  *  heap [In] -- heap from which the table is allocated
152  *  flags [In] -- flags to HeapAlloc
153  *
154  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
155  *  GetIpForwardTable returns otherwise
156  *
157  */
158 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
159  ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
160 {
161   DWORD ret;
162
163   if (!ppIpForwardTable)
164     ret = ERROR_INVALID_PARAMETER;
165   else {
166     DWORD dwSize = 0;
167
168     ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
169     if (ret == ERROR_INSUFFICIENT_BUFFER) {
170       *ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize);
171       ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
172     }
173   }
174   return ret;
175 }
176
177
178 /******************************************************************
179  *    AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
180  *
181  *
182  * PARAMS
183  *
184  *  ppIpNetTable [Out]
185  *  bOrder [In] -- passed to GetIpNetTable to order the table
186  *  heap [In] -- heap from which the table is allocated
187  *  flags [In] -- flags to HeapAlloc
188  *
189  * RETURNS
190  *
191  *  DWORD
192  *
193  */
194 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
195  BOOL bOrder, HANDLE heap, DWORD flags)
196 {
197   DWORD ret;
198
199   if (!ppIpNetTable)
200     ret = ERROR_INVALID_PARAMETER;
201   else {
202     DWORD dwSize = 0;
203
204     ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
205     if (ret == ERROR_INSUFFICIENT_BUFFER) {
206       *ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize);
207       ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
208     }
209   }
210   return ret;
211 }
212
213
214 /******************************************************************
215  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
216  *
217  *
218  * PARAMS
219  *
220  *  ppTcpTable [Out]
221  *  bOrder [In] -- passed to GetTcpTable to order the table
222  *  heap [In] -- heap from which the table is allocated
223  *  flags [In] -- flags to HeapAlloc
224  *
225  * RETURNS
226  *
227  *  DWORD
228  *
229  */
230 DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
231  BOOL bOrder, HANDLE heap, DWORD flags)
232 {
233   DWORD ret;
234
235   if (!ppTcpTable)
236     ret = ERROR_INVALID_PARAMETER;
237   else {
238     DWORD dwSize = 0;
239
240     ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
241     if (ret == ERROR_INSUFFICIENT_BUFFER) {
242       *ppTcpTable = (PMIB_TCPTABLE)HeapAlloc(heap, flags, dwSize);
243       ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
244     }
245   }
246   return ret;
247 }
248
249
250 /******************************************************************
251  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
252  *
253  *
254  * PARAMS
255  *
256  *  ppUdpTable [Out]
257  *  bOrder [In] -- passed to GetUdpTable to order the table
258  *  heap [In] -- heap from which the table is allocated
259  *  flags [In] -- flags to HeapAlloc
260  *
261  * RETURNS
262  *
263  *  DWORD
264  *
265  */
266 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
267  BOOL bOrder, HANDLE heap, DWORD flags)
268 {
269   DWORD ret;
270
271   if (!ppUdpTable)
272     ret = ERROR_INVALID_PARAMETER;
273   else {
274     DWORD dwSize = 0;
275
276     ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
277     if (ret == ERROR_INSUFFICIENT_BUFFER) {
278       *ppUdpTable = (PMIB_UDPTABLE)HeapAlloc(heap, flags, dwSize);
279       ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
280     }
281   }
282   return ret;
283 }
284
285
286 /******************************************************************
287  *    CreateIpForwardEntry (IPHLPAPI.@)
288  *
289  *
290  * PARAMS
291  *
292  *  pRoute [In/Out]
293  *
294  * RETURNS
295  *
296  *  DWORD
297  *
298  */
299 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
300 {
301   /* could use SIOCADDRT, not sure I want to */
302   FIXME(":stub\n");
303   return (DWORD) 0;
304 }
305
306
307 /******************************************************************
308  *    CreateIpNetEntry (IPHLPAPI.@)
309  *
310  *
311  * PARAMS
312  *
313  *  pArpEntry [In/Out]
314  *
315  * RETURNS
316  *
317  *  DWORD
318  *
319  */
320 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
321 {
322   /* could use SIOCSARP on systems that support it, not sure I want to */
323   FIXME(":stub\n");
324   return (DWORD) 0;
325 }
326
327
328 /******************************************************************
329  *    CreateProxyArpEntry (IPHLPAPI.@)
330  *
331  *
332  * PARAMS
333  *
334  *  dwAddress [In]
335  *  dwMask [In]
336  *  dwIfIndex [In]
337  *
338  * RETURNS
339  *
340  *  DWORD
341  *
342  */
343 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
344 {
345   FIXME(":stub\n");
346   /* marking Win2K+ functions not supported */
347   return ERROR_NOT_SUPPORTED;
348 }
349
350
351 /******************************************************************
352  *    DeleteIPAddress (IPHLPAPI.@)
353  *
354  *
355  * PARAMS
356  *
357  *  NTEContext [In]
358  *
359  * RETURNS
360  *
361  *  DWORD
362  *
363  */
364 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
365 {
366   FIXME(":stub\n");
367   /* marking Win2K+ functions not supported */
368   return ERROR_NOT_SUPPORTED;
369 }
370
371
372 /******************************************************************
373  *    DeleteIpForwardEntry (IPHLPAPI.@)
374  *
375  *
376  * PARAMS
377  *
378  *  pRoute [In/Out]
379  *
380  * RETURNS
381  *
382  *  DWORD
383  *
384  */
385 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
386 {
387   /* could use SIOCDELRT, not sure I want to */
388   FIXME(":stub\n");
389   return (DWORD) 0;
390 }
391
392
393 /******************************************************************
394  *    DeleteIpNetEntry (IPHLPAPI.@)
395  *
396  *
397  * PARAMS
398  *
399  *  pArpEntry [In/Out]
400  *
401  * RETURNS
402  *
403  *  DWORD
404  *
405  */
406 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
407 {
408   /* could use SIOCDARP on systems that support it, not sure I want to */
409   FIXME(":stub\n");
410   return (DWORD) 0;
411 }
412
413
414 /******************************************************************
415  *    DeleteProxyArpEntry (IPHLPAPI.@)
416  *
417  *
418  * PARAMS
419  *
420  *  dwAddress [In]
421  *  dwMask [In]
422  *  dwIfIndex [In]
423  *
424  * RETURNS
425  *
426  *  DWORD
427  *
428  */
429 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
430 {
431   FIXME(":stub\n");
432   /* marking Win2K+ functions not supported */
433   return ERROR_NOT_SUPPORTED;
434 }
435
436
437 /******************************************************************
438  *    EnableRouter (IPHLPAPI.@)
439  *
440  *
441  * PARAMS
442  *
443  *  pHandle [In/Out]
444  *  pOverlapped [In/Out]
445  *
446  * RETURNS
447  *
448  *  DWORD
449  *
450  */
451 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
452 {
453   FIXME(":stub\n");
454   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
455      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
456      marking Win2K+ functions not supported */
457   return ERROR_NOT_SUPPORTED;
458 }
459
460
461 /******************************************************************
462  *    FlushIpNetTable (IPHLPAPI.@)
463  *
464  *
465  * PARAMS
466  *
467  *  dwIfIndex [In]
468  *
469  * RETURNS
470  *
471  *  DWORD
472  *
473  */
474 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
475 {
476   FIXME(":stub\n");
477   /* this flushes the arp cache of the given index
478      marking Win2K+ functions not supported */
479   return ERROR_NOT_SUPPORTED;
480 }
481
482
483 /******************************************************************
484  *    GetAdapterIndex (IPHLPAPI.@)
485  *
486  *
487  * PARAMS
488  *
489  *  AdapterName [In/Out]
490  *  IfIndex [In/Out]
491  *
492  * RETURNS
493  *
494  *  DWORD
495  *
496  */
497 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
498 {
499   FIXME(":stub\n");
500   /* marking Win2K+ functions not supported */
501   return ERROR_NOT_SUPPORTED;
502 }
503
504
505 /******************************************************************
506  *    GetAdaptersInfo (IPHLPAPI.@)
507  *
508  *
509  * PARAMS
510  *
511  *  pAdapterInfo [In/Out]
512  *  pOutBufLen [In/Out]
513  *
514  * RETURNS
515  *
516  *  DWORD
517  *
518  */
519 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
520 {
521   DWORD ret;
522
523   if (!pOutBufLen)
524     ret = ERROR_INVALID_PARAMETER;
525   else {
526     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
527
528     if (numNonLoopbackInterfaces > 0) {
529       /* this calculation assumes only one address in the IP_ADDR_STRING lists.
530          that's okay, because:
531          - we don't get multiple addresses per adapter anyway
532          - we don't know about per-adapter gateways
533          - we don't know about DHCP or WINS (and these must be single anyway) */
534       ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
535
536       if (!pAdapterInfo || *pOutBufLen < size) {
537         *pOutBufLen = size;
538         ret = ERROR_BUFFER_OVERFLOW;
539       }
540       else {
541         InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
542
543         if (table) {
544           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
545           if (*pOutBufLen < size) {
546             *pOutBufLen = size;
547             ret = ERROR_INSUFFICIENT_BUFFER;
548           }
549           else {
550             DWORD ndx;
551
552             memset(pAdapterInfo, 0, size);
553             for (ndx = 0; ndx < table->numIndexes; ndx++) {
554               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
555               DWORD addrLen = sizeof(ptr->Address), type;
556
557               /* on Win98 this is left empty, but whatever */
558               strncpy(ptr->AdapterName,
559                getInterfaceNameByIndex(table->indexes[ndx]),
560                sizeof(ptr->AdapterName));
561               ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
562               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
563                ptr->Address, &type);
564               /* MS defines address length and type as UINT in some places and
565                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
566                  PDWORD are equiv (64-bit?) */
567               ptr->AddressLength = addrLen;
568               ptr->Type = type;
569               ptr->Index = table->indexes[ndx];
570               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
571                ptr->IpAddressList.IpAddress.String);
572               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
573                ptr->IpAddressList.IpMask.String);
574               if (ndx < table->numIndexes + 1)
575                 ptr->Next = (ndx == table->numIndexes - 1) ? NULL : &pAdapterInfo[ndx + 1];
576             }
577             ret = NO_ERROR;
578           }
579           free(table);
580         }
581         else
582           ret = ERROR_OUTOFMEMORY;
583       }
584     }
585     else
586       ret = ERROR_NO_DATA;
587   }
588   return ret;
589 }
590
591
592 /******************************************************************
593  *    GetBestInterface (IPHLPAPI.@)
594  *
595  *
596  * PARAMS
597  *
598  *  dwDestAddr [In]
599  *  pdwBestIfIndex [In/Out]
600  *
601  * RETURNS
602  *
603  *  DWORD
604  *
605  */
606 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
607 {
608   DWORD ret;
609
610   if (!pdwBestIfIndex)
611     ret = ERROR_INVALID_PARAMETER;
612   else {
613     MIB_IPFORWARDROW ipRow;
614
615     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
616     if (ret == ERROR_SUCCESS)
617       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
618   }
619   return ret;
620 }
621
622
623 /******************************************************************
624  *    GetBestRoute (IPHLPAPI.@)
625  *
626  *
627  * PARAMS
628  *
629  *  dwDestAddr [In]
630  *  dwSourceAddr [In]
631  *  OUT [In]
632  *
633  * RETURNS
634  *
635  *  DWORD
636  *
637  */
638 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
639 {
640   PMIB_IPFORWARDTABLE table;
641   DWORD ret;
642
643   if (!pBestRoute)
644     return ERROR_INVALID_PARAMETER;
645
646   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
647   if (table) {
648     DWORD ndx, matchedBits, matchedNdx = 0;
649
650     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
651       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
652        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
653         DWORD numShifts, mask;
654
655         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
656          mask && !(mask & 1); mask >>= 1, numShifts++)
657           ;
658         if (numShifts > matchedBits) {
659           matchedBits = numShifts;
660           matchedNdx = ndx;
661         }
662       }
663     }
664     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
665     HeapFree(GetProcessHeap(), 0, table);
666     ret = ERROR_SUCCESS;
667   }
668   else
669     ret = ERROR_OUTOFMEMORY;
670   return ret;
671 }
672
673
674 /******************************************************************
675  *    GetFriendlyIfIndex (IPHLPAPI.@)
676  *
677  *
678  * PARAMS
679  *
680  *  IfIndex [In]
681  *
682  * RETURNS
683  *
684  *  DWORD
685  *
686  */
687 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
688 {
689   /* windows doesn't validate these, either, just makes sure the top byte is
690      cleared.  I assume my ifenum module never gives an index with the top
691      byte set. */
692   return IfIndex;
693 }
694
695
696 /******************************************************************
697  *    GetIcmpStatistics (IPHLPAPI.@)
698  *
699  *
700  * PARAMS
701  *
702  *  pStats [In/Out]
703  *
704  * RETURNS
705  *
706  *  DWORD
707  *
708  */
709 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
710 {
711   return getICMPStats(pStats);
712 }
713
714
715 /******************************************************************
716  *    GetIfEntry (IPHLPAPI.@)
717  *
718  *
719  * PARAMS
720  *
721  *  pIfRow [In/Out]
722  *
723  * RETURNS
724  *
725  *  DWORD
726  *
727  */
728 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
729 {
730   DWORD ret;
731   const char *name;
732
733   if (!pIfRow)
734     return ERROR_INVALID_PARAMETER;
735
736   name = getInterfaceNameByIndex(pIfRow->dwIndex);
737   if (name) {
738     ret = getInterfaceEntryByName(name, pIfRow);
739     if (ret == NO_ERROR)
740       ret = getInterfaceStatsByName(name, pIfRow);
741   }
742   else
743     ret = ERROR_INVALID_DATA;
744   return ret;
745 }
746
747
748 static int IfTableSorter(const void *a, const void *b)
749 {
750   int ret;
751
752   if (a && b)
753     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
754   else
755     ret = 0;
756   return ret;
757 }
758
759
760 /******************************************************************
761  *    GetIfTable (IPHLPAPI.@)
762  *
763  *
764  * PARAMS
765  *
766  *  pIfTable [In/Out]
767  *  pdwSize [In/Out]
768  *  bOrder [In]
769  *
770  * RETURNS
771  *
772  *  DWORD
773  *
774  */
775 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
776 {
777   DWORD ret;
778
779   if (!pdwSize)
780     ret = ERROR_INVALID_PARAMETER;
781   else {
782     DWORD numInterfaces = getNumInterfaces();
783     ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
784
785     if (!pIfTable || *pdwSize < size) {
786       *pdwSize = size;
787       ret = ERROR_INSUFFICIENT_BUFFER;
788     }
789     else {
790       InterfaceIndexTable *table = getInterfaceIndexTable();
791
792       if (table) {
793         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
794          sizeof(MIB_IFROW);
795         if (*pdwSize < size) {
796           *pdwSize = size;
797           ret = ERROR_INSUFFICIENT_BUFFER;
798         }
799         else {
800           DWORD ndx;
801
802           pIfTable->dwNumEntries = 0;
803           for (ndx = 0; ndx < table->numIndexes; ndx++) {
804             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
805             GetIfEntry(&pIfTable->table[ndx]);
806             pIfTable->dwNumEntries++;
807           }
808           if (bOrder)
809             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
810              IfTableSorter);
811           ret = NO_ERROR;
812         }
813         free(table);
814       }
815       else
816         ret = ERROR_OUTOFMEMORY;
817     }
818   }
819   return ret;
820 }
821
822
823 /******************************************************************
824  *    GetInterfaceInfo (IPHLPAPI.@)
825  *
826  *
827  * PARAMS
828  *
829  *  pIfTable [In/Out]
830  *  dwOutBufLen [In/Out]
831  *
832  * RETURNS
833  *
834  *  DWORD
835  *
836  */
837 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
838 {
839   DWORD ret;
840
841   if (!dwOutBufLen)
842     ret = ERROR_INVALID_PARAMETER;
843   else {
844     DWORD numInterfaces = getNumInterfaces();
845     ULONG size = sizeof(IP_INTERFACE_INFO) + (numInterfaces - 1) *
846      sizeof(IP_ADAPTER_INDEX_MAP);
847
848     if (!pIfTable || *dwOutBufLen < size) {
849       *dwOutBufLen = size;
850       ret = ERROR_INSUFFICIENT_BUFFER;
851     }
852     else {
853       InterfaceIndexTable *table = getInterfaceIndexTable();
854
855       if (table) {
856         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes - 1) *
857          sizeof(IP_ADAPTER_INDEX_MAP);
858         if (*dwOutBufLen < size) {
859           *dwOutBufLen = size;
860           ret = ERROR_INSUFFICIENT_BUFFER;
861         }
862         else {
863           DWORD ndx;
864
865           pIfTable->NumAdapters = 0;
866           for (ndx = 0; ndx < table->numIndexes; ndx++) {
867             const char *walker, *name;
868             WCHAR *assigner;
869
870             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
871             name = getInterfaceNameByIndex(table->indexes[ndx]);
872             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
873              walker && *walker &&
874              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
875              walker++, assigner++)
876               *assigner = *walker;
877             *assigner = 0;
878             pIfTable->NumAdapters++;
879           }
880           ret = NO_ERROR;
881         }
882         free(table);
883       }
884       else
885         ret = ERROR_OUTOFMEMORY;
886     }
887   }
888   return ret;
889 }
890
891
892 static int IpAddrTableSorter(const void *a, const void *b)
893 {
894   int ret;
895
896   if (a && b)
897     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
898   else
899     ret = 0;
900   return ret;
901 }
902
903
904 /******************************************************************
905  *    GetIpAddrTable (IPHLPAPI.@)
906  *
907  *
908  * PARAMS
909  *
910  *  pIpAddrTable [In/Out]
911  *  pdwSize [In/Out]
912  *  bOrder [In]
913  *
914  * RETURNS
915  *
916  *  DWORD
917  *
918  */
919 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
920 {
921   DWORD ret;
922
923   if (!pdwSize)
924     ret = ERROR_INVALID_PARAMETER;
925   else {
926     DWORD numInterfaces = getNumInterfaces();
927     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
928      sizeof(MIB_IPADDRROW);
929
930     if (!pIpAddrTable || *pdwSize < size) {
931       *pdwSize = size;
932       ret = ERROR_INSUFFICIENT_BUFFER;
933     }
934     else {
935       InterfaceIndexTable *table = getInterfaceIndexTable();
936
937       if (table) {
938         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
939          sizeof(MIB_IPADDRROW);
940         if (*pdwSize < size) {
941           *pdwSize = size;
942           ret = ERROR_INSUFFICIENT_BUFFER;
943         }
944         else {
945           DWORD ndx;
946
947           pIpAddrTable->dwNumEntries = 0;
948           for (ndx = 0; ndx < table->numIndexes; ndx++) {
949             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
950             pIpAddrTable->table[ndx].dwAddr =
951              getInterfaceIPAddrByIndex(table->indexes[ndx]);
952             pIpAddrTable->table[ndx].dwMask =
953              getInterfaceMaskByIndex(table->indexes[ndx]);
954             pIpAddrTable->table[ndx].dwBCastAddr =
955              getInterfaceBCastAddrByIndex(table->indexes[ndx]);
956             /* FIXME: hardcoded reasm size, not sure where to get it */
957             pIpAddrTable->table[ndx].dwReasmSize = 65535;
958             pIpAddrTable->table[ndx].unused1 = 0;
959             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
960             pIpAddrTable->dwNumEntries++;
961           }
962           if (bOrder)
963             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
964              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
965           ret = NO_ERROR;
966         }
967         free(table);
968       }
969       else
970         ret = ERROR_OUTOFMEMORY;
971     }
972   }
973   return ret;
974 }
975
976
977 static int IpForwardTableSorter(const void *a, const void *b)
978 {
979   int ret;
980
981   if (a && b) {
982     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
983
984     ret = rowA->dwForwardDest - rowB->dwForwardDest;
985     if (ret == 0) {
986       ret = rowA->dwForwardProto - rowB->dwForwardProto;
987       if (ret == 0) {
988         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
989         if (ret == 0)
990           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
991       }
992     }
993   }
994   else
995     ret = 0;
996   return ret;
997 }
998
999
1000 /******************************************************************
1001  *    GetIpForwardTable (IPHLPAPI.@)
1002  *
1003  *
1004  * PARAMS
1005  *
1006  *  pIpForwardTable [In/Out]
1007  *  pdwSize [In/Out]
1008  *  bOrder [In]
1009  *
1010  * RETURNS
1011  *
1012  *  DWORD
1013  *
1014  */
1015 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1016 {
1017   DWORD ret;
1018
1019   if (!pdwSize)
1020     ret = ERROR_INVALID_PARAMETER;
1021   else {
1022     DWORD numRoutes = getNumRoutes();
1023     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1024      sizeof(MIB_IPFORWARDROW);
1025
1026     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1027       *pdwSize = sizeNeeded;
1028       ret = ERROR_INSUFFICIENT_BUFFER;
1029     }
1030     else {
1031       RouteTable *table = getRouteTable();
1032       if (table) {
1033         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1034          sizeof(MIB_IPFORWARDROW);
1035         if (*pdwSize < sizeNeeded) {
1036           *pdwSize = sizeNeeded;
1037           ret = ERROR_INSUFFICIENT_BUFFER;
1038         }
1039         else {
1040           DWORD ndx;
1041
1042           pIpForwardTable->dwNumEntries = table->numRoutes;
1043           for (ndx = 0; ndx < numRoutes; ndx++) {
1044             pIpForwardTable->table[ndx].dwForwardIfIndex =
1045              table->routes[ndx].ifIndex;
1046             pIpForwardTable->table[ndx].dwForwardDest =
1047              table->routes[ndx].dest;
1048             pIpForwardTable->table[ndx].dwForwardMask =
1049              table->routes[ndx].mask;
1050             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1051             pIpForwardTable->table[ndx].dwForwardNextHop =
1052              table->routes[ndx].gateway;
1053             /* FIXME: this type is appropriate for local interfaces; may not
1054                always be appropriate */
1055             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1056             /* FIXME: other protos might be appropriate, e.g. the default route
1057                is typically set with MIB_IPPROTO_NETMGMT instead */
1058             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1059             /* punt on age and AS */
1060             pIpForwardTable->table[ndx].dwForwardAge = 0;
1061             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1062             pIpForwardTable->table[ndx].dwForwardMetric1 =
1063              table->routes[ndx].metric;
1064             /* rest of the metrics are 0.. */
1065             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1066             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1067             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1068             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1069           }
1070           if (bOrder)
1071             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1072              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1073           ret = NO_ERROR;
1074         }
1075         free(table);
1076       }
1077       else
1078         ret = ERROR_OUTOFMEMORY;
1079     }
1080   }
1081   return ret;
1082 }
1083
1084
1085 static int IpNetTableSorter(const void *a, const void *b)
1086 {
1087   int ret;
1088
1089   if (a && b)
1090     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1091   else
1092     ret = 0;
1093   return ret;
1094 }
1095
1096
1097 /******************************************************************
1098  *    GetIpNetTable (IPHLPAPI.@)
1099  *
1100  *
1101  * PARAMS
1102  *
1103  *  pIpNetTable [In/Out]
1104  *  pdwSize [In/Out]
1105  *  bOrder [In]
1106  *
1107  * RETURNS
1108  *
1109  *  DWORD
1110  *
1111  */
1112 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1113 {
1114   DWORD ret;
1115
1116   if (!pdwSize)
1117     ret = ERROR_INVALID_PARAMETER;
1118   else {
1119     DWORD numEntries = getNumArpEntries();
1120     ULONG size = sizeof(MIB_IPNETTABLE) + (numEntries - 1) *
1121      sizeof(MIB_IPNETROW);
1122
1123     if (!pIpNetTable || *pdwSize < size) {
1124       *pdwSize = size;
1125       ret = ERROR_INSUFFICIENT_BUFFER;
1126     }
1127     else {
1128       PMIB_IPNETTABLE table = getArpTable();
1129
1130       if (table) {
1131         size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
1132          sizeof(MIB_IPNETROW);
1133         if (*pdwSize < size) {
1134           *pdwSize = size;
1135           ret = ERROR_INSUFFICIENT_BUFFER;
1136         }
1137         else {
1138           memcpy(pIpNetTable, table, size);
1139           if (bOrder)
1140             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1141              sizeof(MIB_IPNETROW), IpNetTableSorter);
1142           ret = NO_ERROR;
1143         }
1144         free(table);
1145       }
1146       else
1147         ret = ERROR_OUTOFMEMORY;
1148     }
1149   }
1150   return ret;
1151 }
1152
1153
1154 /******************************************************************
1155  *    GetIpStatistics (IPHLPAPI.@)
1156  *
1157  *
1158  * PARAMS
1159  *
1160  *  pStats [In/Out]
1161  *
1162  * RETURNS
1163  *
1164  *  DWORD
1165  *
1166  */
1167 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1168 {
1169   return getIPStats(pStats);
1170 }
1171
1172
1173 /******************************************************************
1174  *    GetNetworkParams (IPHLPAPI.@)
1175  *
1176  *
1177  * PARAMS
1178  *
1179  *  pFixedInfo [In/Out]
1180  *  pOutBufLen [In/Out]
1181  *
1182  * RETURNS
1183  *
1184  *  DWORD
1185  *
1186  */
1187 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1188 {
1189   DWORD size;
1190   HKEY hKey;
1191
1192   if (!pOutBufLen)
1193     return ERROR_INVALID_PARAMETER;
1194
1195   res_init();
1196   size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
1197    sizeof(IP_ADDR_STRING) : 0);
1198   if (!pFixedInfo || *pOutBufLen < size) {
1199     *pOutBufLen = size;
1200     return ERROR_BUFFER_OVERFLOW;
1201   }
1202
1203   memset(pFixedInfo, 0, size);
1204   size = sizeof(pFixedInfo->HostName);
1205   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1206   size = sizeof(pFixedInfo->DomainName);
1207   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1208   if (_res.nscount > 0) {
1209     PIP_ADDR_STRING ptr;
1210     int i;
1211
1212     for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount && ptr;
1213      i++, ptr = ptr->Next) {
1214       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1215        ptr->IpAddress.String);
1216       if (i == _res.nscount - 1)
1217         ptr->Next = NULL;
1218       else if (i == 0)
1219         ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
1220       else
1221         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1222     }
1223   }
1224   pFixedInfo->NodeType = HYBRID_NODETYPE;
1225   if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1226    "\\SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey)
1227    == ERROR_SUCCESS)
1228   {
1229     DWORD size = sizeof(pFixedInfo->ScopeId);
1230
1231     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, pFixedInfo->ScopeId, &size);
1232     RegCloseKey(hKey);
1233   }
1234
1235   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1236      I suppose could also check for a listener on port 53 to set EnableDns */
1237   return NO_ERROR;
1238 }
1239
1240
1241 /******************************************************************
1242  *    GetNumberOfInterfaces (IPHLPAPI.@)
1243  *
1244  *
1245  * PARAMS
1246  *
1247  *  pdwNumIf [In/Out]
1248  *
1249  * RETURNS
1250  *
1251  *  DWORD
1252  *
1253  */
1254 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1255 {
1256   DWORD ret;
1257
1258   if (!pdwNumIf)
1259     ret = ERROR_INVALID_PARAMETER;
1260   else {
1261     *pdwNumIf = getNumInterfaces();
1262     ret = NO_ERROR;
1263   }
1264   return ret;
1265 }
1266
1267
1268 /******************************************************************
1269  *    GetPerAdapterInfo (IPHLPAPI.@)
1270  *
1271  *
1272  * PARAMS
1273  *
1274  *  IfIndex [In]
1275  *  pPerAdapterInfo [In/Out]
1276  *  pOutBufLen [In/Out]
1277  *
1278  * RETURNS
1279  *
1280  *  DWORD
1281  *
1282  */
1283 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1284 {
1285   FIXME(":stub\n");
1286   /* marking Win2K+ functions not supported */
1287   return ERROR_NOT_SUPPORTED;
1288 }
1289
1290
1291 /******************************************************************
1292  *    GetRTTAndHopCount (IPHLPAPI.@)
1293  *
1294  *
1295  * PARAMS
1296  *
1297  *  DestIpAddress [In]
1298  *  HopCount [In/Out]
1299  *  MaxHops [In]
1300  *  RTT [In/Out]
1301  *
1302  * RETURNS
1303  *
1304  *  BOOL
1305  *
1306  */
1307 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1308 {
1309   FIXME(":stub\n");
1310   return (BOOL) 0;
1311 }
1312
1313
1314 /******************************************************************
1315  *    GetTcpStatistics (IPHLPAPI.@)
1316  *
1317  *
1318  * PARAMS
1319  *
1320  *  pStats [In/Out]
1321  *
1322  * RETURNS
1323  *
1324  *  DWORD
1325  *
1326  */
1327 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
1328 {
1329   return getTCPStats(pStats);
1330 }
1331
1332
1333 static int TcpTableSorter(const void *a, const void *b)
1334 {
1335   int ret;
1336
1337   if (a && b) {
1338     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
1339
1340     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1341     if (ret == 0) {
1342       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1343       if (ret == 0) {
1344         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
1345         if (ret == 0)
1346           ret = rowA->dwRemotePort - rowB->dwRemotePort;
1347       }
1348     }
1349   }
1350   else
1351     ret = 0;
1352   return ret;
1353 }
1354
1355
1356 /******************************************************************
1357  *    GetTcpTable (IPHLPAPI.@)
1358  *
1359  *
1360  * PARAMS
1361  *
1362  *  pTcpTable [In/Out]
1363  *  pdwSize [In/Out]
1364  *  bOrder [In]
1365  *
1366  * RETURNS
1367  *
1368  *  DWORD
1369  *
1370  */
1371 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1372 {
1373   DWORD ret;
1374
1375   if (!pdwSize)
1376     ret = ERROR_INVALID_PARAMETER;
1377   else {
1378     DWORD numEntries = getNumTcpEntries();
1379     ULONG size = sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW);
1380
1381     if (!pTcpTable || *pdwSize < size) {
1382       *pdwSize = size;
1383       ret = ERROR_INSUFFICIENT_BUFFER;
1384     }
1385     else {
1386       PMIB_TCPTABLE table = getTcpTable();
1387
1388       if (table) {
1389         size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) *
1390          sizeof(MIB_TCPROW);
1391         if (*pdwSize < size) {
1392           *pdwSize = size;
1393           ret = ERROR_INSUFFICIENT_BUFFER;
1394         }
1395         else {
1396           memcpy(pTcpTable, table, size);
1397           if (bOrder)
1398             qsort(pTcpTable->table, pTcpTable->dwNumEntries,
1399              sizeof(MIB_TCPROW), TcpTableSorter);
1400           ret = NO_ERROR;
1401         }
1402         free(table);
1403       }
1404       else
1405         ret = ERROR_OUTOFMEMORY;
1406     }
1407   }
1408   return ret;
1409 }
1410
1411
1412 /******************************************************************
1413  *    GetUdpStatistics (IPHLPAPI.@)
1414  *
1415  *
1416  * PARAMS
1417  *
1418  *  pStats [In/Out]
1419  *
1420  * RETURNS
1421  *
1422  *  DWORD
1423  *
1424  */
1425 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1426 {
1427   return getUDPStats(pStats);
1428 }
1429
1430
1431 static int UdpTableSorter(const void *a, const void *b)
1432 {
1433   int ret;
1434
1435   if (a && b) {
1436     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1437
1438     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1439     if (ret == 0)
1440       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1441   }
1442   else
1443     ret = 0;
1444   return ret;
1445 }
1446
1447
1448 /******************************************************************
1449  *    GetUdpTable (IPHLPAPI.@)
1450  *
1451  *
1452  * PARAMS
1453  *
1454  *  pUdpTable [In/Out]
1455  *  pdwSize [In/Out]
1456  *  bOrder [In]
1457  *
1458  * RETURNS
1459  *
1460  *  DWORD
1461  *
1462  */
1463 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1464 {
1465   DWORD ret;
1466
1467   if (!pdwSize)
1468     ret = ERROR_INVALID_PARAMETER;
1469   else {
1470     DWORD numEntries = getNumUdpEntries();
1471     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1472
1473     if (!pUdpTable || *pdwSize < size) {
1474       *pdwSize = size;
1475       ret = ERROR_INSUFFICIENT_BUFFER;
1476     }
1477     else {
1478       PMIB_UDPTABLE table = getUdpTable();
1479
1480       if (table) {
1481         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1482          sizeof(MIB_UDPROW);
1483         if (*pdwSize < size) {
1484           *pdwSize = size;
1485           ret = ERROR_INSUFFICIENT_BUFFER;
1486         }
1487         else {
1488           memcpy(pUdpTable, table, size);
1489           if (bOrder)
1490             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1491              sizeof(MIB_UDPROW), UdpTableSorter);
1492           ret = NO_ERROR;
1493         }
1494         free(table);
1495       }
1496       else
1497         ret = ERROR_OUTOFMEMORY;
1498     }
1499   }
1500   return ret;
1501 }
1502
1503
1504 /******************************************************************
1505  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1506  *
1507  *
1508  * PARAMS
1509  *
1510  *  pIPIfInfo [In/Out]
1511  *  dwOutBufLen [In/Out]
1512  *
1513  * RETURNS
1514  *
1515  *  DWORD
1516  *
1517  */
1518 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1519 {
1520   /* a unidirectional adapter?? not bloody likely! */
1521   return ERROR_NOT_SUPPORTED;
1522 }
1523
1524
1525 /******************************************************************
1526  *    IpReleaseAddress (IPHLPAPI.@)
1527  *
1528  *
1529  * PARAMS
1530  *
1531  *  AdapterInfo [In/Out]
1532  *
1533  * RETURNS
1534  *
1535  *  DWORD
1536  *
1537  */
1538 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1539 {
1540   /* not a stub, never going to support this (and I never mark an adapter as
1541      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1542   return ERROR_NOT_SUPPORTED;
1543 }
1544
1545
1546 /******************************************************************
1547  *    IpRenewAddress (IPHLPAPI.@)
1548  *
1549  *
1550  * PARAMS
1551  *
1552  *  AdapterInfo [In/Out]
1553  *
1554  * RETURNS
1555  *
1556  *  DWORD
1557  *
1558  */
1559 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1560 {
1561   /* not a stub, never going to support this (and I never mark an adapter as
1562      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1563   return ERROR_NOT_SUPPORTED;
1564 }
1565
1566
1567 /******************************************************************
1568  *    NotifyAddrChange (IPHLPAPI.@)
1569  *
1570  *
1571  * PARAMS
1572  *
1573  *  Handle [In/Out]
1574  *  overlapped [In/Out]
1575  *
1576  * RETURNS
1577  *
1578  *  DWORD
1579  *
1580  */
1581 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1582 {
1583   FIXME(":stub\n");
1584   /* marking Win2K+ functions not supported */
1585   return ERROR_NOT_SUPPORTED;
1586 }
1587
1588
1589 /******************************************************************
1590  *    NotifyRouteChange (IPHLPAPI.@)
1591  *
1592  *
1593  * PARAMS
1594  *
1595  *  Handle [In/Out]
1596  *  overlapped [In/Out]
1597  *
1598  * RETURNS
1599  *
1600  *  DWORD
1601  *
1602  */
1603 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1604 {
1605   FIXME(":stub\n");
1606   /* marking Win2K+ functions not supported */
1607   return ERROR_NOT_SUPPORTED;
1608 }
1609
1610
1611 /******************************************************************
1612  *    SendARP (IPHLPAPI.@)
1613  *
1614  *
1615  * PARAMS
1616  *
1617  *  DestIP [In]
1618  *  SrcIP [In]
1619  *  pMacAddr [In/Out]
1620  *  PhyAddrLen [In/Out]
1621  *
1622  * RETURNS
1623  *
1624  *  DWORD
1625  *
1626  */
1627 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1628 {
1629   FIXME(":stub\n");
1630   /* marking Win2K+ functions not supported */
1631   return ERROR_NOT_SUPPORTED;
1632 }
1633
1634
1635 /******************************************************************
1636  *    SetIfEntry (IPHLPAPI.@)
1637  *
1638  *
1639  * PARAMS
1640  *
1641  *  pIfRow [In/Out]
1642  *
1643  * RETURNS
1644  *
1645  *  DWORD
1646  *
1647  */
1648 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1649 {
1650   /* this is supposed to set an administratively interface up or down.
1651      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1652      this sort of down is indistinguishable from other sorts of down (e.g. no
1653      link). */
1654   FIXME(":stub\n");
1655   return ERROR_NOT_SUPPORTED;
1656 }
1657
1658
1659 /******************************************************************
1660  *    SetIpForwardEntry (IPHLPAPI.@)
1661  *
1662  *
1663  * PARAMS
1664  *
1665  *  pRoute [In/Out]
1666  *
1667  * RETURNS
1668  *
1669  *  DWORD
1670  *
1671  */
1672 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1673 {
1674   /* this is to add a route entry, how's it distinguishable from
1675      CreateIpForwardEntry?
1676      could use SIOCADDRT, not sure I want to */
1677   FIXME(":stub\n");
1678   return (DWORD) 0;
1679 }
1680
1681
1682 /******************************************************************
1683  *    SetIpNetEntry (IPHLPAPI.@)
1684  *
1685  *
1686  * PARAMS
1687  *
1688  *  pArpEntry [In/Out]
1689  *
1690  * RETURNS
1691  *
1692  *  DWORD
1693  *
1694  */
1695 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1696 {
1697   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1698   FIXME(":stub\n");
1699   return (DWORD) 0;
1700 }
1701
1702
1703 /******************************************************************
1704  *    SetIpStatistics (IPHLPAPI.@)
1705  *
1706  *
1707  * PARAMS
1708  *
1709  *  pIpStats [In/Out]
1710  *
1711  * RETURNS
1712  *
1713  *  DWORD
1714  *
1715  */
1716 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1717 {
1718   FIXME(":stub\n");
1719   return (DWORD) 0;
1720 }
1721
1722
1723 /******************************************************************
1724  *    SetIpTTL (IPHLPAPI.@)
1725  *
1726  *
1727  * PARAMS
1728  *
1729  *  nTTL [In]
1730  *
1731  * RETURNS
1732  *
1733  *  DWORD
1734  *
1735  */
1736 DWORD WINAPI SetIpTTL(UINT nTTL)
1737 {
1738   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
1739      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
1740   FIXME(":stub\n");
1741   return (DWORD) 0;
1742 }
1743
1744
1745 /******************************************************************
1746  *    SetTcpEntry (IPHLPAPI.@)
1747  *
1748  *
1749  * PARAMS
1750  *
1751  *  pTcpRow [In/Out]
1752  *
1753  * RETURNS
1754  *
1755  *  DWORD
1756  *
1757  */
1758 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
1759 {
1760   FIXME(":stub\n");
1761   return (DWORD) 0;
1762 }
1763
1764
1765 /******************************************************************
1766  *    UnenableRouter (IPHLPAPI.@)
1767  *
1768  *
1769  * PARAMS
1770  *
1771  *  pOverlapped [In/Out]
1772  *  lpdwEnableCount [In/Out]
1773  *
1774  * RETURNS
1775  *
1776  *  DWORD
1777  *
1778  */
1779 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
1780 {
1781   FIXME(":stub\n");
1782   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
1783      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
1784      marking Win2K+ functions not supported */
1785   return ERROR_NOT_SUPPORTED;
1786 }