INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[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 = &pAdapterInfo[ndx + 1];
576               else
577                 ptr->Next = NULL;
578             }
579             ret = NO_ERROR;
580           }
581           free(table);
582         }
583         else
584           ret = ERROR_OUTOFMEMORY;
585       }
586     }
587     else
588       ret = ERROR_NO_DATA;
589   }
590   return ret;
591 }
592
593
594 /******************************************************************
595  *    GetBestInterface (IPHLPAPI.@)
596  *
597  *
598  * PARAMS
599  *
600  *  dwDestAddr [In]
601  *  pdwBestIfIndex [In/Out]
602  *
603  * RETURNS
604  *
605  *  DWORD
606  *
607  */
608 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
609 {
610   DWORD ret;
611
612   if (!pdwBestIfIndex)
613     ret = ERROR_INVALID_PARAMETER;
614   else {
615     MIB_IPFORWARDROW ipRow;
616
617     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
618     if (ret == ERROR_SUCCESS)
619       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
620   }
621   return ret;
622 }
623
624
625 /******************************************************************
626  *    GetBestRoute (IPHLPAPI.@)
627  *
628  *
629  * PARAMS
630  *
631  *  dwDestAddr [In]
632  *  dwSourceAddr [In]
633  *  OUT [In]
634  *
635  * RETURNS
636  *
637  *  DWORD
638  *
639  */
640 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
641 {
642   PMIB_IPFORWARDTABLE table;
643   DWORD ret;
644
645   if (!pBestRoute)
646     return ERROR_INVALID_PARAMETER;
647
648   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
649   if (table) {
650     DWORD ndx, matchedBits, matchedNdx = 0;
651
652     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
653       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
654        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
655         DWORD numShifts, mask;
656
657         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
658          mask && !(mask & 1); mask >>= 1, numShifts++)
659           ;
660         if (numShifts > matchedBits) {
661           matchedBits = numShifts;
662           matchedNdx = ndx;
663         }
664       }
665     }
666     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
667     HeapFree(GetProcessHeap(), 0, table);
668     ret = ERROR_SUCCESS;
669   }
670   else
671     ret = ERROR_OUTOFMEMORY;
672   return ret;
673 }
674
675
676 /******************************************************************
677  *    GetFriendlyIfIndex (IPHLPAPI.@)
678  *
679  *
680  * PARAMS
681  *
682  *  IfIndex [In]
683  *
684  * RETURNS
685  *
686  *  DWORD
687  *
688  */
689 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
690 {
691   /* windows doesn't validate these, either, just makes sure the top byte is
692      cleared.  I assume my ifenum module never gives an index with the top
693      byte set. */
694   return IfIndex;
695 }
696
697
698 /******************************************************************
699  *    GetIcmpStatistics (IPHLPAPI.@)
700  *
701  *
702  * PARAMS
703  *
704  *  pStats [In/Out]
705  *
706  * RETURNS
707  *
708  *  DWORD
709  *
710  */
711 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
712 {
713   return getICMPStats(pStats);
714 }
715
716
717 /******************************************************************
718  *    GetIfEntry (IPHLPAPI.@)
719  *
720  *
721  * PARAMS
722  *
723  *  pIfRow [In/Out]
724  *
725  * RETURNS
726  *
727  *  DWORD
728  *
729  */
730 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
731 {
732   DWORD ret;
733   const char *name;
734
735   if (!pIfRow)
736     return ERROR_INVALID_PARAMETER;
737
738   name = getInterfaceNameByIndex(pIfRow->dwIndex);
739   if (name) {
740     ret = getInterfaceEntryByName(name, pIfRow);
741     if (ret == NO_ERROR)
742       ret = getInterfaceStatsByName(name, pIfRow);
743   }
744   else
745     ret = ERROR_INVALID_DATA;
746   return ret;
747 }
748
749
750 static int IfTableSorter(const void *a, const void *b)
751 {
752   int ret;
753
754   if (a && b)
755     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
756   else
757     ret = 0;
758   return ret;
759 }
760
761
762 /******************************************************************
763  *    GetIfTable (IPHLPAPI.@)
764  *
765  *
766  * PARAMS
767  *
768  *  pIfTable [In/Out]
769  *  pdwSize [In/Out]
770  *  bOrder [In]
771  *
772  * RETURNS
773  *
774  *  DWORD
775  *
776  */
777 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
778 {
779   DWORD ret;
780
781   if (!pdwSize)
782     ret = ERROR_INVALID_PARAMETER;
783   else {
784     DWORD numInterfaces = getNumInterfaces();
785     ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
786
787     if (!pIfTable || *pdwSize < size) {
788       *pdwSize = size;
789       ret = ERROR_INSUFFICIENT_BUFFER;
790     }
791     else {
792       InterfaceIndexTable *table = getInterfaceIndexTable();
793
794       if (table) {
795         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
796          sizeof(MIB_IFROW);
797         if (*pdwSize < size) {
798           *pdwSize = size;
799           ret = ERROR_INSUFFICIENT_BUFFER;
800         }
801         else {
802           DWORD ndx;
803
804           pIfTable->dwNumEntries = 0;
805           for (ndx = 0; ndx < table->numIndexes; ndx++) {
806             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
807             GetIfEntry(&pIfTable->table[ndx]);
808             pIfTable->dwNumEntries++;
809           }
810           if (bOrder)
811             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
812              IfTableSorter);
813           ret = NO_ERROR;
814         }
815         free(table);
816       }
817       else
818         ret = ERROR_OUTOFMEMORY;
819     }
820   }
821   return ret;
822 }
823
824
825 /******************************************************************
826  *    GetInterfaceInfo (IPHLPAPI.@)
827  *
828  *
829  * PARAMS
830  *
831  *  pIfTable [In/Out]
832  *  dwOutBufLen [In/Out]
833  *
834  * RETURNS
835  *
836  *  DWORD
837  *
838  */
839 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
840 {
841   DWORD ret;
842
843   if (!dwOutBufLen)
844     ret = ERROR_INVALID_PARAMETER;
845   else {
846     DWORD numInterfaces = getNumInterfaces();
847     ULONG size = sizeof(IP_INTERFACE_INFO) + (numInterfaces - 1) *
848      sizeof(IP_ADAPTER_INDEX_MAP);
849
850     if (!pIfTable || *dwOutBufLen < size) {
851       *dwOutBufLen = size;
852       ret = ERROR_INSUFFICIENT_BUFFER;
853     }
854     else {
855       InterfaceIndexTable *table = getInterfaceIndexTable();
856
857       if (table) {
858         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes - 1) *
859          sizeof(IP_ADAPTER_INDEX_MAP);
860         if (*dwOutBufLen < size) {
861           *dwOutBufLen = size;
862           ret = ERROR_INSUFFICIENT_BUFFER;
863         }
864         else {
865           DWORD ndx;
866
867           pIfTable->NumAdapters = 0;
868           for (ndx = 0; ndx < table->numIndexes; ndx++) {
869             const char *walker, *name;
870             WCHAR *assigner;
871
872             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
873             name = getInterfaceNameByIndex(table->indexes[ndx]);
874             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
875              walker && *walker &&
876              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
877              walker++, assigner++)
878               *assigner = *walker;
879             *assigner = 0;
880             pIfTable->NumAdapters++;
881           }
882           ret = NO_ERROR;
883         }
884         free(table);
885       }
886       else
887         ret = ERROR_OUTOFMEMORY;
888     }
889   }
890   return ret;
891 }
892
893
894 static int IpAddrTableSorter(const void *a, const void *b)
895 {
896   int ret;
897
898   if (a && b)
899     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
900   else
901     ret = 0;
902   return ret;
903 }
904
905
906 /******************************************************************
907  *    GetIpAddrTable (IPHLPAPI.@)
908  *
909  *
910  * PARAMS
911  *
912  *  pIpAddrTable [In/Out]
913  *  pdwSize [In/Out]
914  *  bOrder [In]
915  *
916  * RETURNS
917  *
918  *  DWORD
919  *
920  */
921 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
922 {
923   DWORD ret;
924
925   if (!pdwSize)
926     ret = ERROR_INVALID_PARAMETER;
927   else {
928     DWORD numInterfaces = getNumInterfaces();
929     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
930      sizeof(MIB_IPADDRROW);
931
932     if (!pIpAddrTable || *pdwSize < size) {
933       *pdwSize = size;
934       ret = ERROR_INSUFFICIENT_BUFFER;
935     }
936     else {
937       InterfaceIndexTable *table = getInterfaceIndexTable();
938
939       if (table) {
940         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
941          sizeof(MIB_IPADDRROW);
942         if (*pdwSize < size) {
943           *pdwSize = size;
944           ret = ERROR_INSUFFICIENT_BUFFER;
945         }
946         else {
947           DWORD ndx;
948
949           pIpAddrTable->dwNumEntries = 0;
950           for (ndx = 0; ndx < table->numIndexes; ndx++) {
951             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
952             pIpAddrTable->table[ndx].dwAddr =
953              getInterfaceIPAddrByIndex(table->indexes[ndx]);
954             pIpAddrTable->table[ndx].dwMask =
955              getInterfaceMaskByIndex(table->indexes[ndx]);
956             pIpAddrTable->table[ndx].dwBCastAddr =
957              getInterfaceBCastAddrByIndex(table->indexes[ndx]);
958             /* FIXME: hardcoded reasm size, not sure where to get it */
959             pIpAddrTable->table[ndx].dwReasmSize = 65535;
960             pIpAddrTable->table[ndx].unused1 = 0;
961             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
962             pIpAddrTable->dwNumEntries++;
963           }
964           if (bOrder)
965             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
966              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
967           ret = NO_ERROR;
968         }
969         free(table);
970       }
971       else
972         ret = ERROR_OUTOFMEMORY;
973     }
974   }
975   return ret;
976 }
977
978
979 static int IpForwardTableSorter(const void *a, const void *b)
980 {
981   int ret;
982
983   if (a && b) {
984     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
985
986     ret = rowA->dwForwardDest - rowB->dwForwardDest;
987     if (ret == 0) {
988       ret = rowA->dwForwardProto - rowB->dwForwardProto;
989       if (ret == 0) {
990         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
991         if (ret == 0)
992           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
993       }
994     }
995   }
996   else
997     ret = 0;
998   return ret;
999 }
1000
1001
1002 /******************************************************************
1003  *    GetIpForwardTable (IPHLPAPI.@)
1004  *
1005  *
1006  * PARAMS
1007  *
1008  *  pIpForwardTable [In/Out]
1009  *  pdwSize [In/Out]
1010  *  bOrder [In]
1011  *
1012  * RETURNS
1013  *
1014  *  DWORD
1015  *
1016  */
1017 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1018 {
1019   DWORD ret;
1020
1021   if (!pdwSize)
1022     ret = ERROR_INVALID_PARAMETER;
1023   else {
1024     DWORD numRoutes = getNumRoutes();
1025     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1026      sizeof(MIB_IPFORWARDROW);
1027
1028     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1029       *pdwSize = sizeNeeded;
1030       ret = ERROR_INSUFFICIENT_BUFFER;
1031     }
1032     else {
1033       RouteTable *table = getRouteTable();
1034       if (table) {
1035         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1036          sizeof(MIB_IPFORWARDROW);
1037         if (*pdwSize < sizeNeeded) {
1038           *pdwSize = sizeNeeded;
1039           ret = ERROR_INSUFFICIENT_BUFFER;
1040         }
1041         else {
1042           DWORD ndx;
1043
1044           pIpForwardTable->dwNumEntries = table->numRoutes;
1045           for (ndx = 0; ndx < numRoutes; ndx++) {
1046             pIpForwardTable->table[ndx].dwForwardIfIndex =
1047              table->routes[ndx].ifIndex;
1048             pIpForwardTable->table[ndx].dwForwardDest =
1049              table->routes[ndx].dest;
1050             pIpForwardTable->table[ndx].dwForwardMask =
1051              table->routes[ndx].mask;
1052             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1053             pIpForwardTable->table[ndx].dwForwardNextHop =
1054              table->routes[ndx].gateway;
1055             /* FIXME: this type is appropriate for local interfaces; may not
1056                always be appropriate */
1057             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1058             /* FIXME: other protos might be appropriate, e.g. the default route
1059                is typically set with MIB_IPPROTO_NETMGMT instead */
1060             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1061             /* punt on age and AS */
1062             pIpForwardTable->table[ndx].dwForwardAge = 0;
1063             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1064             pIpForwardTable->table[ndx].dwForwardMetric1 =
1065              table->routes[ndx].metric;
1066             /* rest of the metrics are 0.. */
1067             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1068             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1069             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1070             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1071           }
1072           if (bOrder)
1073             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1074              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1075           ret = NO_ERROR;
1076         }
1077         free(table);
1078       }
1079       else
1080         ret = ERROR_OUTOFMEMORY;
1081     }
1082   }
1083   return ret;
1084 }
1085
1086
1087 static int IpNetTableSorter(const void *a, const void *b)
1088 {
1089   int ret;
1090
1091   if (a && b)
1092     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1093   else
1094     ret = 0;
1095   return ret;
1096 }
1097
1098
1099 /******************************************************************
1100  *    GetIpNetTable (IPHLPAPI.@)
1101  *
1102  *
1103  * PARAMS
1104  *
1105  *  pIpNetTable [In/Out]
1106  *  pdwSize [In/Out]
1107  *  bOrder [In]
1108  *
1109  * RETURNS
1110  *
1111  *  DWORD
1112  *
1113  */
1114 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1115 {
1116   DWORD ret;
1117
1118   if (!pdwSize)
1119     ret = ERROR_INVALID_PARAMETER;
1120   else {
1121     DWORD numEntries = getNumArpEntries();
1122     ULONG size = sizeof(MIB_IPNETTABLE) + (numEntries - 1) *
1123      sizeof(MIB_IPNETROW);
1124
1125     if (!pIpNetTable || *pdwSize < size) {
1126       *pdwSize = size;
1127       ret = ERROR_INSUFFICIENT_BUFFER;
1128     }
1129     else {
1130       PMIB_IPNETTABLE table = getArpTable();
1131
1132       if (table) {
1133         size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
1134          sizeof(MIB_IPNETROW);
1135         if (*pdwSize < size) {
1136           *pdwSize = size;
1137           ret = ERROR_INSUFFICIENT_BUFFER;
1138         }
1139         else {
1140           memcpy(pIpNetTable, table, size);
1141           if (bOrder)
1142             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1143              sizeof(MIB_IPNETROW), IpNetTableSorter);
1144           ret = NO_ERROR;
1145         }
1146         free(table);
1147       }
1148       else
1149         ret = ERROR_OUTOFMEMORY;
1150     }
1151   }
1152   return ret;
1153 }
1154
1155
1156 /******************************************************************
1157  *    GetIpStatistics (IPHLPAPI.@)
1158  *
1159  *
1160  * PARAMS
1161  *
1162  *  pStats [In/Out]
1163  *
1164  * RETURNS
1165  *
1166  *  DWORD
1167  *
1168  */
1169 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1170 {
1171   return getIPStats(pStats);
1172 }
1173
1174
1175 /******************************************************************
1176  *    GetNetworkParams (IPHLPAPI.@)
1177  *
1178  *
1179  * PARAMS
1180  *
1181  *  pFixedInfo [In/Out]
1182  *  pOutBufLen [In/Out]
1183  *
1184  * RETURNS
1185  *
1186  *  DWORD
1187  *
1188  */
1189 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1190 {
1191   DWORD size;
1192   HKEY hKey;
1193
1194   if (!pOutBufLen)
1195     return ERROR_INVALID_PARAMETER;
1196
1197   res_init();
1198   size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
1199    sizeof(IP_ADDR_STRING) : 0);
1200   if (!pFixedInfo || *pOutBufLen < size) {
1201     *pOutBufLen = size;
1202     return ERROR_BUFFER_OVERFLOW;
1203   }
1204
1205   memset(pFixedInfo, 0, size);
1206   size = sizeof(pFixedInfo->HostName);
1207   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1208   size = sizeof(pFixedInfo->DomainName);
1209   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1210   if (_res.nscount > 0) {
1211     PIP_ADDR_STRING ptr;
1212     int i;
1213
1214     for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount && ptr;
1215      i++, ptr = ptr->Next) {
1216       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1217        ptr->IpAddress.String);
1218       if (i == _res.nscount - 1)
1219         ptr->Next = NULL;
1220       else if (i == 0)
1221         ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
1222       else
1223         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1224     }
1225   }
1226   pFixedInfo->NodeType = HYBRID_NODETYPE;
1227   if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1228    "\\SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey)
1229    == ERROR_SUCCESS)
1230   {
1231     DWORD size = sizeof(pFixedInfo->ScopeId);
1232
1233     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, pFixedInfo->ScopeId, &size);
1234     RegCloseKey(hKey);
1235   }
1236
1237   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1238      I suppose could also check for a listener on port 53 to set EnableDns */
1239   return NO_ERROR;
1240 }
1241
1242
1243 /******************************************************************
1244  *    GetNumberOfInterfaces (IPHLPAPI.@)
1245  *
1246  *
1247  * PARAMS
1248  *
1249  *  pdwNumIf [In/Out]
1250  *
1251  * RETURNS
1252  *
1253  *  DWORD
1254  *
1255  */
1256 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1257 {
1258   DWORD ret;
1259
1260   if (!pdwNumIf)
1261     ret = ERROR_INVALID_PARAMETER;
1262   else {
1263     *pdwNumIf = getNumInterfaces();
1264     ret = NO_ERROR;
1265   }
1266   return ret;
1267 }
1268
1269
1270 /******************************************************************
1271  *    GetPerAdapterInfo (IPHLPAPI.@)
1272  *
1273  *
1274  * PARAMS
1275  *
1276  *  IfIndex [In]
1277  *  pPerAdapterInfo [In/Out]
1278  *  pOutBufLen [In/Out]
1279  *
1280  * RETURNS
1281  *
1282  *  DWORD
1283  *
1284  */
1285 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1286 {
1287   FIXME(":stub\n");
1288   /* marking Win2K+ functions not supported */
1289   return ERROR_NOT_SUPPORTED;
1290 }
1291
1292
1293 /******************************************************************
1294  *    GetRTTAndHopCount (IPHLPAPI.@)
1295  *
1296  *
1297  * PARAMS
1298  *
1299  *  DestIpAddress [In]
1300  *  HopCount [In/Out]
1301  *  MaxHops [In]
1302  *  RTT [In/Out]
1303  *
1304  * RETURNS
1305  *
1306  *  BOOL
1307  *
1308  */
1309 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1310 {
1311   FIXME(":stub\n");
1312   return (BOOL) 0;
1313 }
1314
1315
1316 /******************************************************************
1317  *    GetTcpStatistics (IPHLPAPI.@)
1318  *
1319  *
1320  * PARAMS
1321  *
1322  *  pStats [In/Out]
1323  *
1324  * RETURNS
1325  *
1326  *  DWORD
1327  *
1328  */
1329 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
1330 {
1331   return getTCPStats(pStats);
1332 }
1333
1334
1335 static int TcpTableSorter(const void *a, const void *b)
1336 {
1337   int ret;
1338
1339   if (a && b) {
1340     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
1341
1342     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1343     if (ret == 0) {
1344       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1345       if (ret == 0) {
1346         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
1347         if (ret == 0)
1348           ret = rowA->dwRemotePort - rowB->dwRemotePort;
1349       }
1350     }
1351   }
1352   else
1353     ret = 0;
1354   return ret;
1355 }
1356
1357
1358 /******************************************************************
1359  *    GetTcpTable (IPHLPAPI.@)
1360  *
1361  *
1362  * PARAMS
1363  *
1364  *  pTcpTable [In/Out]
1365  *  pdwSize [In/Out]
1366  *  bOrder [In]
1367  *
1368  * RETURNS
1369  *
1370  *  DWORD
1371  *
1372  */
1373 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1374 {
1375   DWORD ret;
1376
1377   if (!pdwSize)
1378     ret = ERROR_INVALID_PARAMETER;
1379   else {
1380     DWORD numEntries = getNumTcpEntries();
1381     ULONG size = sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW);
1382
1383     if (!pTcpTable || *pdwSize < size) {
1384       *pdwSize = size;
1385       ret = ERROR_INSUFFICIENT_BUFFER;
1386     }
1387     else {
1388       PMIB_TCPTABLE table = getTcpTable();
1389
1390       if (table) {
1391         size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) *
1392          sizeof(MIB_TCPROW);
1393         if (*pdwSize < size) {
1394           *pdwSize = size;
1395           ret = ERROR_INSUFFICIENT_BUFFER;
1396         }
1397         else {
1398           memcpy(pTcpTable, table, size);
1399           if (bOrder)
1400             qsort(pTcpTable->table, pTcpTable->dwNumEntries,
1401              sizeof(MIB_TCPROW), TcpTableSorter);
1402           ret = NO_ERROR;
1403         }
1404         free(table);
1405       }
1406       else
1407         ret = ERROR_OUTOFMEMORY;
1408     }
1409   }
1410   return ret;
1411 }
1412
1413
1414 /******************************************************************
1415  *    GetUdpStatistics (IPHLPAPI.@)
1416  *
1417  *
1418  * PARAMS
1419  *
1420  *  pStats [In/Out]
1421  *
1422  * RETURNS
1423  *
1424  *  DWORD
1425  *
1426  */
1427 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1428 {
1429   return getUDPStats(pStats);
1430 }
1431
1432
1433 static int UdpTableSorter(const void *a, const void *b)
1434 {
1435   int ret;
1436
1437   if (a && b) {
1438     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1439
1440     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1441     if (ret == 0)
1442       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1443   }
1444   else
1445     ret = 0;
1446   return ret;
1447 }
1448
1449
1450 /******************************************************************
1451  *    GetUdpTable (IPHLPAPI.@)
1452  *
1453  *
1454  * PARAMS
1455  *
1456  *  pUdpTable [In/Out]
1457  *  pdwSize [In/Out]
1458  *  bOrder [In]
1459  *
1460  * RETURNS
1461  *
1462  *  DWORD
1463  *
1464  */
1465 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1466 {
1467   DWORD ret;
1468
1469   if (!pdwSize)
1470     ret = ERROR_INVALID_PARAMETER;
1471   else {
1472     DWORD numEntries = getNumUdpEntries();
1473     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1474
1475     if (!pUdpTable || *pdwSize < size) {
1476       *pdwSize = size;
1477       ret = ERROR_INSUFFICIENT_BUFFER;
1478     }
1479     else {
1480       PMIB_UDPTABLE table = getUdpTable();
1481
1482       if (table) {
1483         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1484          sizeof(MIB_UDPROW);
1485         if (*pdwSize < size) {
1486           *pdwSize = size;
1487           ret = ERROR_INSUFFICIENT_BUFFER;
1488         }
1489         else {
1490           memcpy(pUdpTable, table, size);
1491           if (bOrder)
1492             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1493              sizeof(MIB_UDPROW), UdpTableSorter);
1494           ret = NO_ERROR;
1495         }
1496         free(table);
1497       }
1498       else
1499         ret = ERROR_OUTOFMEMORY;
1500     }
1501   }
1502   return ret;
1503 }
1504
1505
1506 /******************************************************************
1507  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1508  *
1509  *
1510  * PARAMS
1511  *
1512  *  pIPIfInfo [In/Out]
1513  *  dwOutBufLen [In/Out]
1514  *
1515  * RETURNS
1516  *
1517  *  DWORD
1518  *
1519  */
1520 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1521 {
1522   /* a unidirectional adapter?? not bloody likely! */
1523   return ERROR_NOT_SUPPORTED;
1524 }
1525
1526
1527 /******************************************************************
1528  *    IpReleaseAddress (IPHLPAPI.@)
1529  *
1530  *
1531  * PARAMS
1532  *
1533  *  AdapterInfo [In/Out]
1534  *
1535  * RETURNS
1536  *
1537  *  DWORD
1538  *
1539  */
1540 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1541 {
1542   /* not a stub, never going to support this (and I never mark an adapter as
1543      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1544   return ERROR_NOT_SUPPORTED;
1545 }
1546
1547
1548 /******************************************************************
1549  *    IpRenewAddress (IPHLPAPI.@)
1550  *
1551  *
1552  * PARAMS
1553  *
1554  *  AdapterInfo [In/Out]
1555  *
1556  * RETURNS
1557  *
1558  *  DWORD
1559  *
1560  */
1561 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1562 {
1563   /* not a stub, never going to support this (and I never mark an adapter as
1564      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1565   return ERROR_NOT_SUPPORTED;
1566 }
1567
1568
1569 /******************************************************************
1570  *    NotifyAddrChange (IPHLPAPI.@)
1571  *
1572  *
1573  * PARAMS
1574  *
1575  *  Handle [In/Out]
1576  *  overlapped [In/Out]
1577  *
1578  * RETURNS
1579  *
1580  *  DWORD
1581  *
1582  */
1583 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1584 {
1585   FIXME(":stub\n");
1586   /* marking Win2K+ functions not supported */
1587   return ERROR_NOT_SUPPORTED;
1588 }
1589
1590
1591 /******************************************************************
1592  *    NotifyRouteChange (IPHLPAPI.@)
1593  *
1594  *
1595  * PARAMS
1596  *
1597  *  Handle [In/Out]
1598  *  overlapped [In/Out]
1599  *
1600  * RETURNS
1601  *
1602  *  DWORD
1603  *
1604  */
1605 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1606 {
1607   FIXME(":stub\n");
1608   /* marking Win2K+ functions not supported */
1609   return ERROR_NOT_SUPPORTED;
1610 }
1611
1612
1613 /******************************************************************
1614  *    SendARP (IPHLPAPI.@)
1615  *
1616  *
1617  * PARAMS
1618  *
1619  *  DestIP [In]
1620  *  SrcIP [In]
1621  *  pMacAddr [In/Out]
1622  *  PhyAddrLen [In/Out]
1623  *
1624  * RETURNS
1625  *
1626  *  DWORD
1627  *
1628  */
1629 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1630 {
1631   FIXME(":stub\n");
1632   /* marking Win2K+ functions not supported */
1633   return ERROR_NOT_SUPPORTED;
1634 }
1635
1636
1637 /******************************************************************
1638  *    SetIfEntry (IPHLPAPI.@)
1639  *
1640  *
1641  * PARAMS
1642  *
1643  *  pIfRow [In/Out]
1644  *
1645  * RETURNS
1646  *
1647  *  DWORD
1648  *
1649  */
1650 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1651 {
1652   /* this is supposed to set an administratively interface up or down.
1653      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1654      this sort of down is indistinguishable from other sorts of down (e.g. no
1655      link). */
1656   FIXME(":stub\n");
1657   return ERROR_NOT_SUPPORTED;
1658 }
1659
1660
1661 /******************************************************************
1662  *    SetIpForwardEntry (IPHLPAPI.@)
1663  *
1664  *
1665  * PARAMS
1666  *
1667  *  pRoute [In/Out]
1668  *
1669  * RETURNS
1670  *
1671  *  DWORD
1672  *
1673  */
1674 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1675 {
1676   /* this is to add a route entry, how's it distinguishable from
1677      CreateIpForwardEntry?
1678      could use SIOCADDRT, not sure I want to */
1679   FIXME(":stub\n");
1680   return (DWORD) 0;
1681 }
1682
1683
1684 /******************************************************************
1685  *    SetIpNetEntry (IPHLPAPI.@)
1686  *
1687  *
1688  * PARAMS
1689  *
1690  *  pArpEntry [In/Out]
1691  *
1692  * RETURNS
1693  *
1694  *  DWORD
1695  *
1696  */
1697 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1698 {
1699   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1700   FIXME(":stub\n");
1701   return (DWORD) 0;
1702 }
1703
1704
1705 /******************************************************************
1706  *    SetIpStatistics (IPHLPAPI.@)
1707  *
1708  *
1709  * PARAMS
1710  *
1711  *  pIpStats [In/Out]
1712  *
1713  * RETURNS
1714  *
1715  *  DWORD
1716  *
1717  */
1718 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1719 {
1720   FIXME(":stub\n");
1721   return (DWORD) 0;
1722 }
1723
1724
1725 /******************************************************************
1726  *    SetIpTTL (IPHLPAPI.@)
1727  *
1728  *
1729  * PARAMS
1730  *
1731  *  nTTL [In]
1732  *
1733  * RETURNS
1734  *
1735  *  DWORD
1736  *
1737  */
1738 DWORD WINAPI SetIpTTL(UINT nTTL)
1739 {
1740   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
1741      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
1742   FIXME(":stub\n");
1743   return (DWORD) 0;
1744 }
1745
1746
1747 /******************************************************************
1748  *    SetTcpEntry (IPHLPAPI.@)
1749  *
1750  *
1751  * PARAMS
1752  *
1753  *  pTcpRow [In/Out]
1754  *
1755  * RETURNS
1756  *
1757  *  DWORD
1758  *
1759  */
1760 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
1761 {
1762   FIXME(":stub\n");
1763   return (DWORD) 0;
1764 }
1765
1766
1767 /******************************************************************
1768  *    UnenableRouter (IPHLPAPI.@)
1769  *
1770  *
1771  * PARAMS
1772  *
1773  *  pOverlapped [In/Out]
1774  *  lpdwEnableCount [In/Out]
1775  *
1776  * RETURNS
1777  *
1778  *  DWORD
1779  *
1780  */
1781 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
1782 {
1783   FIXME(":stub\n");
1784   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
1785      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
1786      marking Win2K+ functions not supported */
1787   return ERROR_NOT_SUPPORTED;
1788 }