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